HarmonyOS NEXT Development Case: Latitude and Longitude Distance Calculation
The following example demonstrates how to implement a distance calculator between geographic coordinates using HarmonyOS NEXT's declarative development paradigm. This case leverages ArkUI components and the MapKit module to create a responsive interface with real-time distance calculation capabilities. Key Features Dual-column input for coordinates (longitude/latitude) Real-time distance calculation using MapKit APIs Example preset (Beijing to Shanghai) Responsive UI with focus states Data clearing functionality Kilometer-based distance display Code Implementation (with English Comments) import { mapCommon } from '@kit.MapKit'; // Import map common module import { map } from '@kit.MapKit'; // Import map module @Entry // Entry decorator for application entry component @Component // Component decorator struct DistanceCalculator { // Distance calculator component structure @State private primaryColor: string = '#fea024'; // Primary theme color @State private fontColor: string = "#2e2e2e"; // Main text color @State private isStartFocused: boolean = false; // Start point input focus state @State private isEndFocused: boolean = false; // End point input focus state @State private isSecondStartFocused: boolean = false; // Second start point focus @State private isSecondEndFocused: boolean = false; // Second end point focus @State private baseSpacing: number = 30; // Base spacing unit @State @Watch('onInputChange') private startLongitude: string = ""; // Start longitude @State @Watch('onInputChange') private startLatitude: string = ""; // Start latitude @State @Watch('onInputChange') private endLongitude: string = ""; // End longitude @State @Watch('onInputChange') private endLatitude: string = ""; // End latitude @State distance: number = 0; // Calculated distance aboutToAppear(): void { // Component lifecycle hook this.onInputChange(); // Initial calculation } onInputChange() { // Input change handler let fromLatLng: mapCommon.LatLng = { // Start coordinate object latitude: Number(this.startLatitude), longitude: Number(this.startLongitude) }; let toLatLng: mapCommon.LatLng = { // End coordinate object latitude: Number(this.endLatitude), longitude: Number(this.endLongitude) }; this.distance = map.calculateDistance(fromLatLng, toLatLng); // Calculate distance } build() { // UI construction Column() { // Main vertical layout // Header section Text("Coordinate Distance Calculator") .width('100%') .height(54) .fontSize(18) .fontWeight(FontWeight.Bold) .backgroundColor(Color.White) .textAlign(TextAlign.Center) .fontColor(this.fontColor); // Input area Column() { Row() { // Example presets row Text('Example (Beijing->Shanghai)') .fontColor("#5871ce") .fontSize(18) .padding(`${this.baseSpacing / 2}lpx`) .backgroundColor("#f2f1fd") .borderRadius(5) .clickEffect({ level: ClickEffectLevel.LIGHT, scale: 0.8 }) .onClick(() => { // Preset coordinates this.startLongitude = "116.4074"; // Beijing longitude this.startLatitude = "39.9042"; // Beijing latitude this.endLongitude = "121.4737"; // Shanghai longitude this.endLatitude = "31.2304"; // Shanghai latitude }); Blank(); // Spacer Text('Clear All') .fontColor("#e48742") .fontSize(18) .padding(`${this.baseSpacing / 2}lpx`) .clickEffect({ level: ClickEffectLevel.LIGHT, scale: 0.8 }) .backgroundColor("#ffefe6") .borderRadius(5) .onClick(() => { // Clear inputs this.startLongitude = ""; this.startLatitude = ""; this.endLongitude = ""; this.endLatitude = ""; }); }.height(45) .justifyContent(FlexAlign.SpaceBetween) .width('100%'); Divider().margin({ top: 5, bottom: 5 }); // Start point inputs Row() { Text('Start Point') .fontWeight(FontWeight.Bold) .fontSize(18) .fontColor(this.fontColor); }.margin({ bottom: `${this.baseSpacing}lpx`, top: `${this.baseSpacing}lpx` }); Row() { // Longitude/Latitude inputs TextInput({ text: $$this.startLongitude, placeholder: 'Longitude' }) .caretColor(this.primaryColor) .layoutWeight(1) .type(InputType.NUMBER_DECIMAL) .placeholderColor(this.isStartFocused ? this.primaryColor : Color.Gray) .fontColor(this.isStartFocused ? this.primaryColor : this.fontColor) .borderColor(this.isStartFocused ? this.primaryColor : Color.Gray) .borderWidth(1) .borderRadius(10) .backgroundColor(Color.White)

The following example demonstrates how to implement a distance calculator between geographic coordinates using HarmonyOS NEXT's declarative development paradigm. This case leverages ArkUI components and the MapKit module to create a responsive interface with real-time distance calculation capabilities.
Key Features
- Dual-column input for coordinates (longitude/latitude)
- Real-time distance calculation using MapKit APIs
- Example preset (Beijing to Shanghai)
- Responsive UI with focus states
- Data clearing functionality
- Kilometer-based distance display
Code Implementation (with English Comments)
import { mapCommon } from '@kit.MapKit'; // Import map common module
import { map } from '@kit.MapKit'; // Import map module
@Entry // Entry decorator for application entry component
@Component // Component decorator
struct DistanceCalculator { // Distance calculator component structure
@State private primaryColor: string = '#fea024'; // Primary theme color
@State private fontColor: string = "#2e2e2e"; // Main text color
@State private isStartFocused: boolean = false; // Start point input focus state
@State private isEndFocused: boolean = false; // End point input focus state
@State private isSecondStartFocused: boolean = false; // Second start point focus
@State private isSecondEndFocused: boolean = false; // Second end point focus
@State private baseSpacing: number = 30; // Base spacing unit
@State @Watch('onInputChange') private startLongitude: string = ""; // Start longitude
@State @Watch('onInputChange') private startLatitude: string = ""; // Start latitude
@State @Watch('onInputChange') private endLongitude: string = ""; // End longitude
@State @Watch('onInputChange') private endLatitude: string = ""; // End latitude
@State distance: number = 0; // Calculated distance
aboutToAppear(): void { // Component lifecycle hook
this.onInputChange(); // Initial calculation
}
onInputChange() { // Input change handler
let fromLatLng: mapCommon.LatLng = { // Start coordinate object
latitude: Number(this.startLatitude),
longitude: Number(this.startLongitude)
};
let toLatLng: mapCommon.LatLng = { // End coordinate object
latitude: Number(this.endLatitude),
longitude: Number(this.endLongitude)
};
this.distance = map.calculateDistance(fromLatLng, toLatLng); // Calculate distance
}
build() { // UI construction
Column() { // Main vertical layout
// Header section
Text("Coordinate Distance Calculator")
.width('100%')
.height(54)
.fontSize(18)
.fontWeight(FontWeight.Bold)
.backgroundColor(Color.White)
.textAlign(TextAlign.Center)
.fontColor(this.fontColor);
// Input area
Column() {
Row() { // Example presets row
Text('Example (Beijing->Shanghai)')
.fontColor("#5871ce")
.fontSize(18)
.padding(`${this.baseSpacing / 2}lpx`)
.backgroundColor("#f2f1fd")
.borderRadius(5)
.clickEffect({ level: ClickEffectLevel.LIGHT, scale: 0.8 })
.onClick(() => { // Preset coordinates
this.startLongitude = "116.4074"; // Beijing longitude
this.startLatitude = "39.9042"; // Beijing latitude
this.endLongitude = "121.4737"; // Shanghai longitude
this.endLatitude = "31.2304"; // Shanghai latitude
});
Blank(); // Spacer
Text('Clear All')
.fontColor("#e48742")
.fontSize(18)
.padding(`${this.baseSpacing / 2}lpx`)
.clickEffect({ level: ClickEffectLevel.LIGHT, scale: 0.8 })
.backgroundColor("#ffefe6")
.borderRadius(5)
.onClick(() => { // Clear inputs
this.startLongitude = "";
this.startLatitude = "";
this.endLongitude = "";
this.endLatitude = "";
});
}.height(45)
.justifyContent(FlexAlign.SpaceBetween)
.width('100%');
Divider().margin({ top: 5, bottom: 5 });
// Start point inputs
Row() {
Text('Start Point')
.fontWeight(FontWeight.Bold)
.fontSize(18)
.fontColor(this.fontColor);
}.margin({ bottom: `${this.baseSpacing}lpx`, top: `${this.baseSpacing}lpx` });
Row() { // Longitude/Latitude inputs
TextInput({ text: $$this.startLongitude, placeholder: 'Longitude' })
.caretColor(this.primaryColor)
.layoutWeight(1)
.type(InputType.NUMBER_DECIMAL)
.placeholderColor(this.isStartFocused ? this.primaryColor : Color.Gray)
.fontColor(this.isStartFocused ? this.primaryColor : this.fontColor)
.borderColor(this.isStartFocused ? this.primaryColor : Color.Gray)
.borderWidth(1)
.borderRadius(10)
.backgroundColor(Color.White)
.showUnderline(false)
.onBlur(() => this.isStartFocused = false)
.onFocus(() => this.isStartFocused = true);
Line().width(10);
TextInput({ text: $$this.startLatitude, placeholder: 'Latitude' })
.caretColor(this.primaryColor)
.layoutWeight(1)
.type(InputType.NUMBER_DECIMAL)
.placeholderColor(this.isEndFocused ? this.primaryColor : Color.Gray)
.fontColor(this.isEndFocused ? this.primaryColor : this.fontColor)
.borderColor(this.isEndFocused ? this.primaryColor : Color.Gray)
.borderWidth(1)
.borderRadius(10)
.backgroundColor(Color.White)
.showUnderline(false)
.onBlur(() => this.isEndFocused = false)
.onFocus(() => this.isEndFocused = true);
}
// End point inputs
Text('End Point')
.fontWeight(FontWeight.Bold)
.fontSize(18)
.fontColor(this.fontColor)
.margin({ bottom: `${this.baseSpacing}lpx`, top: `${this.baseSpacing}lpx` });
Row() {
TextInput({ text: $$this.endLongitude, placeholder: 'Longitude' })
.caretColor(this.primaryColor)
.layoutWeight(1)
.type(InputType.NUMBER_DECIMAL)
.placeholderColor(this.isSecondStartFocused ? this.primaryColor : Color.Gray)
.fontColor(this.isSecondStartFocused ? this.primaryColor : this.fontColor)
.borderColor(this.isSecondStartFocused ? this.primaryColor : Color.Gray)
.borderWidth(1)
.borderRadius(10)
.backgroundColor(Color.White)
.showUnderline(false)
.onBlur(() => this.isSecondStartFocused = false)
.onFocus(() => this.isSecondStartFocused = true);
Line().width(10);
TextInput({ text: $$this.endLatitude, placeholder: 'Latitude' })
.caretColor(this.primaryColor)
.layoutWeight(1)
.type(InputType.NUMBER_DECIMAL)
.placeholderColor(this.isSecondEndFocused ? this.primaryColor : Color.Gray)
.fontColor(this.isSecondEndFocused ? this.primaryColor : this.fontColor)
.borderColor(this.isSecondEndFocused ? this.primaryColor : Color.Gray)
.borderWidth(1)
.borderRadius(10)
.backgroundColor(Color.White)
.showUnderline(false)
.onBlur(() => this.isSecondEndFocused = false)
.onFocus(() => this.isSecondEndFocused = true);
}
}.width('650lpx')
.padding(`${this.baseSpacing}lpx`)
.margin({ top: 20 })
.backgroundColor(Color.White)
.borderRadius(10)
.alignItems(HorizontalAlign.Start);
// Result display
Column() {
Text() {
Span(`Distance: `)
Span(`${(this.distance / 1000).toFixed(2)} `).fontColor(this.primaryColor)
Span(`kilometers`)
}
.fontWeight(FontWeight.Bold)
.fontSize(18)
.fontColor(this.fontColor);
}.width('650lpx')
.backgroundColor(Color.White)
.borderRadius(10)
.padding(`${this.baseSpacing}lpx`)
.margin({ top: `${this.baseSpacing}lpx` })
.alignItems(HorizontalAlign.Start);
}
.height('100%')
.width('100%')
.backgroundColor("#eff0f3");
}
}
Implementation Details
- State Management:
- Uses
@State
decorators for reactive UI updates -
@Watch
decorator triggers recalculation on input changes Manages focus states for visual feedback
Map Integration:
Utilizes
map.calculateDistance()
from MapKitConverts string inputs to numeric coordinates
Returns distance in meters (converted to kilometers)
UI Features:
Responsive layout using percentage-based widths
Visual feedback for input focus states
Clean material design-inspired aesthetics
Adaptive color schemes
Smooth animations for user interactions
Validation:
Input type restricted to decimal numbers
Automatic handling of invalid inputs (returns 0 distance)
Empty state management
This implementation demonstrates HarmonyOS NEXT's capabilities in creating sophisticated location-based applications with clean, maintainable code. The declarative UI approach combined with reactive programming patterns enables efficient development of complex interactive applications.