鴻蒙NEXT開發(fā)案例:經(jīng)緯度距離計(jì)算

c.gif

【引言】

在鴻蒙NEXT平臺(tái)上,我們可以輕松地開發(fā)出一個(gè)經(jīng)緯度距離計(jì)算器,幫助用戶快速計(jì)算兩點(diǎn)之間的距離。本文將詳細(xì)介紹如何在鴻蒙NEXT中實(shí)現(xiàn)這一功能,通過簡單的用戶界面和高效的計(jì)算邏輯,為用戶提供便捷的服務(wù)。

【環(huán)境準(zhǔn)備】

? 操作系統(tǒng):Windows 10

? 開發(fā)工具:DevEco Studio NEXT Beta1 Build Version: 5.0.3.806

? 目標(biāo)設(shè)備:華為Mate60 Pro

? 開發(fā)語言:ArkTS

? 框架:ArkUI

? API版本:API 12

【思路】

在本案例中,我們將創(chuàng)建一個(gè)名為“距離計(jì)算器”的組件,用戶可以輸入起點(diǎn)和終點(diǎn)的經(jīng)緯度,系統(tǒng)將自動(dòng)計(jì)算并顯示兩點(diǎn)之間的距離。以下是實(shí)現(xiàn)的主要思路:

1 組件結(jié)構(gòu)設(shè)計(jì):

使用Column和Row布局組件來組織界面元素,使其具有良好的可讀性和用戶體驗(yàn)。在界面頂部添加標(biāo)題,明確應(yīng)用的功能。

2 輸入?yún)^(qū)域:

提供兩個(gè)輸入框,分別用于輸入起點(diǎn)和終點(diǎn)的經(jīng)緯度。用戶可以手動(dòng)輸入,也可以通過點(diǎn)擊示例按鈕快速填充常用位置(如北京和上海)。設(shè)計(jì)清空按鈕,方便用戶快速重置輸入。

3 狀態(tài)管理:

使用@State裝飾器管理組件的狀態(tài),包括輸入框的聚焦?fàn)顟B(tài)、經(jīng)緯度值和計(jì)算結(jié)果。通過@Watch裝飾器監(jiān)視輸入變化,確保在用戶輸入經(jīng)緯度時(shí),能夠?qū)崟r(shí)更新計(jì)算結(jié)果。

4 距離計(jì)算邏輯:在輸入變化時(shí),調(diào)用地圖模塊的calculateDistance方法,計(jì)算兩點(diǎn)之間的距離,并將結(jié)果更新到界面上。結(jié)果以公里為單位顯示,確保用戶能夠直觀理解計(jì)算結(jié)果。

5 界面美化:通過設(shè)置顏色、邊框、圓角等樣式,使界面更加美觀和用戶友好。使用適當(dāng)?shù)淖煮w和大小,確保信息的清晰可讀。

【完整代碼】

import { mapCommon } from '@kit.MapKit'; // 導(dǎo)入地圖通用模塊
import { map } from '@kit.MapKit'; // 導(dǎo)入地圖模塊

@Entry // 入口裝飾器,標(biāo)識(shí)該組件為應(yīng)用的入口
@Component // 組件裝飾器,定義一個(gè)組件
struct DistanceCalculator { // 定義一個(gè)名為 DistanceCalculator 的結(jié)構(gòu)體
  @State private primaryColor: string = '#fea024'; // 定義主題顏色,初始值為橙色
  @State private fontColor: string = "#2e2e2e"; // 定義字體顏色,初始值為深灰色
  @State private isStartFocused: boolean = false; // 定義起點(diǎn)輸入框的聚焦?fàn)顟B(tài),初始為 false
  @State private isEndFocused: boolean = false; // 定義終點(diǎn)輸入框的聚焦?fàn)顟B(tài),初始為 false
  @State private isSecondStartFocused: boolean = false; // 定義第二起點(diǎn)輸入框的聚焦?fàn)顟B(tài),初始為 false
  @State private isSecondEndFocused: boolean = false; // 定義第二終點(diǎn)輸入框的聚焦?fàn)顟B(tài),初始為 false
  @State private baseSpacing: number = 30; // 定義基礎(chǔ)間距,初始值為 30
  @State @Watch('onInputChange') private startLongitude: string = ""; // 定義起點(diǎn)經(jīng)度,初始為空,并監(jiān)視輸入變化
  @State @Watch('onInputChange') private startLatitude: string = ""; // 定義起點(diǎn)緯度,初始為空,并監(jiān)視輸入變化
  @State @Watch('onInputChange') private endLongitude: string = ""; // 定義終點(diǎn)經(jīng)度,初始為空,并監(jiān)視輸入變化
  @State @Watch('onInputChange') private endLatitude: string = ""; // 定義終點(diǎn)緯度,初始為空,并監(jiān)視輸入變化
  @State distance: number = 0; // 定義兩點(diǎn)之間的距離,初始值為 0

  aboutToAppear(): void { // 生命周期鉤子函數(shù),組件即將顯示時(shí)調(diào)用
    this.onInputChange(); // 調(diào)用輸入變化處理函數(shù)以初始化
  }

  onInputChange() { // 輸入變化處理函數(shù)
    let fromLatLng: mapCommon.LatLng = { // 創(chuàng)建起點(diǎn)經(jīng)緯度對(duì)象
      latitude: Number(this.startLatitude), // 將起點(diǎn)緯度轉(zhuǎn)換為數(shù)字
      longitude: Number(this.startLongitude) // 將起點(diǎn)經(jīng)度轉(zhuǎn)換為數(shù)字
    };
    let toLatLng: mapCommon.LatLng = { // 創(chuàng)建終點(diǎn)經(jīng)緯度對(duì)象
      latitude: Number(this.endLatitude), // 將終點(diǎn)緯度轉(zhuǎn)換為數(shù)字
      longitude: Number(this.endLongitude) // 將終點(diǎn)經(jīng)度轉(zhuǎn)換為數(shù)字
    };
    this.distance = map.calculateDistance(fromLatLng, toLatLng); // 計(jì)算起點(diǎn)和終點(diǎn)之間的距離
  }

  build() { // 構(gòu)建界面函數(shù)
    Column() { // 垂直布局容器
      // 標(biāo)題欄,展示應(yīng)用名
      Text("經(jīng)緯度距離計(jì)算") // 創(chuàng)建文本組件,顯示標(biāo)題
        .width('100%') // 設(shè)置寬度為 100%
        .height(54) // 設(shè)置高度為 54 像素
        .fontSize(18) // 設(shè)置字體大小為 18
        .fontWeight(600) // 設(shè)置字體粗細(xì)為 600
        .backgroundColor(Color.White) // 設(shè)置背景顏色為白色
        .textAlign(TextAlign.Center) // 設(shè)置文本對(duì)齊方式為居中
        .fontColor(this.fontColor); // 設(shè)置字體顏色為定義的字體顏色

      // 輸入?yún)^(qū)域
      Column() { // 垂直布局容器
        Row() { // 水平布局容器
          Text('示例(北京-->上海)') // 創(chuàng)建文本組件,顯示示例信息
            .fontColor("#5871ce") // 設(shè)置字體顏色為藍(lán)色
            .fontSize(18) // 設(shè)置字體大小為 18
            .padding(`${this.baseSpacing / 2}lpx`) // 設(shè)置內(nèi)邊距
            .backgroundColor("#f2f1fd") // 設(shè)置背景顏色
            .borderRadius(5) // 設(shè)置圓角半徑為 5
            .clickEffect({ level: ClickEffectLevel.LIGHT, scale: 0.8 }) // 設(shè)置點(diǎn)擊效果
            .onClick(() => { // 點(diǎn)擊事件處理
              this.startLongitude = "116.4074"; // 設(shè)置起點(diǎn)經(jīng)度為北京經(jīng)度
              this.startLatitude = "39.9042"; // 設(shè)置起點(diǎn)緯度為北京緯度
              this.endLongitude = "121.4737"; // 設(shè)置終點(diǎn)經(jīng)度為上海經(jīng)度
              this.endLatitude = "31.2304"; // 設(shè)置終點(diǎn)緯度為上海緯度
            });
          Blank(); // 占位符,用于占據(jù)空間
          Text('清空') // 創(chuàng)建文本組件,顯示“清空”按鈕
            .fontColor("#e48742") // 設(shè)置字體顏色為橙色
            .fontSize(18) // 設(shè)置字體大小為 18
            .padding(`${this.baseSpacing / 2}lpx`) // 設(shè)置內(nèi)邊距
            .clickEffect({ level: ClickEffectLevel.LIGHT, scale: 0.8 }) // 設(shè)置點(diǎn)擊效果
            .backgroundColor("#ffefe6") // 設(shè)置背景顏色
            .borderRadius(5) // 設(shè)置圓角半徑為 5
            .onClick(() => { // 點(diǎn)擊事件處理
              this.startLongitude = ""; // 清空起點(diǎn)經(jīng)度
              this.startLatitude = ""; // 清空起點(diǎn)緯度
              this.endLongitude = ""; // 清空終點(diǎn)經(jīng)度
              this.endLatitude = ""; // 清空終點(diǎn)緯度
            });
        }.height(45) // 設(shè)置行高為 45 像素
        .justifyContent(FlexAlign.SpaceBetween) // 設(shè)置子元素在主軸上的對(duì)齊方式
        .width('100%'); // 設(shè)置寬度為 100%

        Divider().margin({ top: 5, bottom: 5 }); // 創(chuàng)建分隔符,設(shè)置上下邊距

        // 起點(diǎn)輸入
        Row() { // 水平布局容器
          Text('起點(diǎn)') // 創(chuàng)建文本組件,顯示“起點(diǎn)”
            .fontWeight(600) // 設(shè)置字體粗細(xì)為 600
            .fontSize(18) // 設(shè)置字體大小為 18
            .fontColor(this.fontColor); // 設(shè)置字體顏色為定義的字體顏色
        }
        .margin({ bottom: `${this.baseSpacing}lpx`, top: `${this.baseSpacing}lpx` }); // 設(shè)置上下邊距

        Row() { // 水平布局容器
          TextInput({ text: $$this.startLongitude, placeholder: '經(jīng)度' }) // 創(chuàng)建起點(diǎn)經(jīng)度輸入框
            .caretColor(this.primaryColor) // 設(shè)置光標(biāo)顏色為主題顏色
            .layoutWeight(1) // 設(shè)置布局權(quán)重
            .type(InputType.NUMBER_DECIMAL) // 設(shè)置輸入類型為小數(shù)
            .placeholderColor(this.isStartFocused ? this.primaryColor : Color.Gray) // 設(shè)置占位符顏色
            .fontColor(this.isStartFocused ? this.primaryColor : this.fontColor) // 設(shè)置字體顏色
            .borderColor(this.isStartFocused ? this.primaryColor : Color.Gray) // 設(shè)置邊框顏色
            .borderWidth(1) // 設(shè)置邊框?qū)挾?            .borderRadius(10) // 設(shè)置圓角半徑為 10
            .backgroundColor(Color.White) // 設(shè)置背景顏色為白色
            .showUnderline(false) // 不顯示下劃線
            .onBlur(() => this.isStartFocused = false) // 失去焦點(diǎn)時(shí)設(shè)置聚焦?fàn)顟B(tài)為 false
            .onFocus(() => this.isStartFocused = true); // 獲得焦點(diǎn)時(shí)設(shè)置聚焦?fàn)顟B(tài)為 true

          Line().width(10); // 創(chuàng)建分隔符,設(shè)置寬度為 10 像素

          TextInput({ text: $$this.startLatitude, placeholder: '緯度' }) // 創(chuàng)建起點(diǎn)緯度輸入框
            .caretColor(this.primaryColor) // 設(shè)置光標(biāo)顏色為主題顏色
            .layoutWeight(1) // 設(shè)置布局權(quán)重
            .type(InputType.NUMBER_DECIMAL) // 設(shè)置輸入類型為小數(shù)
            .placeholderColor(this.isEndFocused ? this.primaryColor : Color.Gray) // 設(shè)置占位符顏色
            .fontColor(this.isEndFocused ? this.primaryColor : this.fontColor) // 設(shè)置字體顏色
            .borderColor(this.isEndFocused ? this.primaryColor : Color.Gray) // 設(shè)置邊框顏色
            .borderWidth(1) // 設(shè)置邊框?qū)挾?            .borderRadius(10) // 設(shè)置圓角半徑為 10
            .backgroundColor(Color.White) // 設(shè)置背景顏色為白色
            .showUnderline(false) // 不顯示下劃線
            .onBlur(() => this.isEndFocused = false) // 失去焦點(diǎn)時(shí)設(shè)置聚焦?fàn)顟B(tài)為 false
            .onFocus(() => this.isEndFocused = true); // 獲得焦點(diǎn)時(shí)設(shè)置聚焦?fàn)顟B(tài)為 true
        }

        // 終點(diǎn)輸入
        Text('終點(diǎn)') // 創(chuàng)建文本組件,顯示“終點(diǎn)”
          .fontWeight(600) // 設(shè)置字體粗細(xì)為 600
          .fontSize(18) // 設(shè)置字體大小為 18
          .fontColor(this.fontColor) // 設(shè)置字體顏色為定義的字體顏色
          .margin({ bottom: `${this.baseSpacing}lpx`, top: `${this.baseSpacing}lpx` }); // 設(shè)置上下邊距

        Row() { // 水平布局容器
          TextInput({ text: $$this.endLongitude, placeholder: '經(jīng)度' }) // 創(chuàng)建終點(diǎn)經(jīng)度輸入框
            .caretColor(this.primaryColor) // 設(shè)置光標(biāo)顏色為主題顏色
            .layoutWeight(1) // 設(shè)置布局權(quán)重
            .type(InputType.NUMBER_DECIMAL) // 設(shè)置輸入類型為小數(shù)
            .placeholderColor(this.isSecondStartFocused ? this.primaryColor : Color.Gray) // 設(shè)置占位符顏色
            .fontColor(this.isSecondStartFocused ? this.primaryColor : this.fontColor) // 設(shè)置字體顏色
            .borderColor(this.isSecondStartFocused ? this.primaryColor : Color.Gray) // 設(shè)置邊框顏色
            .borderWidth(1) // 設(shè)置邊框?qū)挾?            .borderRadius(10) // 設(shè)置圓角半徑為 10
            .backgroundColor(Color.White) // 設(shè)置背景顏色為白色
            .showUnderline(false) // 不顯示下劃線
            .onBlur(() => this.isSecondStartFocused = false) // 失去焦點(diǎn)時(shí)設(shè)置聚焦?fàn)顟B(tài)為 false
            .onFocus(() => this.isSecondStartFocused = true); // 獲得焦點(diǎn)時(shí)設(shè)置聚焦?fàn)顟B(tài)為 true

          Line().width(10); // 創(chuàng)建分隔符,設(shè)置寬度為 10 像素

          TextInput({ text: $$this.endLatitude, placeholder: '緯度' }) // 創(chuàng)建終點(diǎn)緯度輸入框
            .caretColor(this.primaryColor) // 設(shè)置光標(biāo)顏色為主題顏色
            .layoutWeight(1) // 設(shè)置布局權(quán)重
            .type(InputType.NUMBER_DECIMAL) // 設(shè)置輸入類型為小數(shù)
            .placeholderColor(this.isSecondEndFocused ? this.primaryColor : Color.Gray) // 設(shè)置占位符顏色
            .fontColor(this.isSecondEndFocused ? this.primaryColor : this.fontColor) // 設(shè)置字體顏色
            .borderColor(this.isSecondEndFocused ? this.primaryColor : Color.Gray) // 設(shè)置邊框顏色
            .borderWidth(1) // 設(shè)置邊框?qū)挾?            .borderRadius(10) // 設(shè)置圓角半徑為 10
            .backgroundColor(Color.White) // 設(shè)置背景顏色為白色
            .showUnderline(false) // 不顯示下劃線
            .onBlur(() => this.isSecondEndFocused = false) // 失去焦點(diǎn)時(shí)設(shè)置聚焦?fàn)顟B(tài)為 false
            .onFocus(() => this.isSecondEndFocused = true); // 獲得焦點(diǎn)時(shí)設(shè)置聚焦?fàn)顟B(tài)為 true
        }
      }
      .width('650lpx') // 設(shè)置輸入?yún)^(qū)域?qū)挾葹?650 像素
      .padding(`${this.baseSpacing}lpx`) // 設(shè)置內(nèi)邊距
      .margin({ top: 20 }) // 設(shè)置上邊距為 20 像素
      .backgroundColor(Color.White) // 設(shè)置背景顏色為白色
      .borderRadius(10) // 設(shè)置圓角半徑為 10
      .alignItems(HorizontalAlign.Start); // 設(shè)置子元素在交叉軸上的對(duì)齊方式

      // 顯示計(jì)算結(jié)果
      Column() { // 垂直布局容器
        Text() { // 文本組件
          Span(`兩點(diǎn)之間的距離是:`) // 創(chuàng)建文本片段,顯示提示信息
          Span(`${(this.distance / 1000).toFixed(2)} `).fontColor(this.primaryColor) // 創(chuàng)建文本片段,顯示距離(公里),并設(shè)置顏色
          Span(`公里`) // 創(chuàng)建文本片段,顯示單位“公里”
        }
        .fontWeight(600) // 設(shè)置字體粗細(xì)為 600
        .fontSize(18) // 設(shè)置字體大小為 18
        .fontColor(this.fontColor); // 設(shè)置字體顏色為定義的字體顏色
      }
      .width('650lpx') // 設(shè)置結(jié)果顯示區(qū)域?qū)挾葹?650 像素
      .backgroundColor(Color.White) // 設(shè)置背景顏色為白色
      .borderRadius(10) // 設(shè)置圓角半徑為 10
      .padding(`${this.baseSpacing}lpx`) // 設(shè)置內(nèi)邊距
      .margin({ top: `${this.baseSpacing}lpx` }) // 設(shè)置上邊距
      .alignItems(HorizontalAlign.Start); // 設(shè)置子元素在交叉軸上的對(duì)齊方式
    }
    .height('100%') // 設(shè)置整個(gè)組件高度為 100%
    .width('100%') // 設(shè)置整個(gè)組件寬度為 100%
    .backgroundColor("#eff0f3"); // 設(shè)置背景顏色為淺灰色
  }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容