探索HarmonyOS位置服务:为用户提供直观的坐标显示

电子说

1.3w人已加入

描述

关于作者
白晓明
宁夏图尔科技有限公司董事长兼CEO、坚果派联合创始人
华为HDE、润和软件HiHope社区专家、鸿蒙KOL、仓颉KOL
华为开发者学堂/51CTO学堂/CSDN学堂认证讲师
开放原子开源基金会2023开源贡献之星
OpenHarmony三方库贡献者
公众号:开源开发者新视界(openwatcher)

在先前的环节中,我们所获取到的位置信息是以经纬度的方式来呈现。不可否认,这种呈现方式在描述位置时具有极高的准确性,能够精确地定位到地球的每一个点。然而,不得不承认的是,对于普通用户而言,经纬度的表述形式显示得过于专业和晦涩,缺乏直观性和易理解性,确实不够友好。

而HarmonyOS的位置服务(Location Kit)则犹如一位贴心的助手,为开发者提供了地理编码转化和逆地理编码转化这两种极为实用的能力。其中,地理编码就像是一个信息丰富的宝藏,它包含了多个属性来对位置进行细致入微的描述。比如,它涵盖了国家这个宏观层面的标识,让我们能够快速确定位置所在的大区域;还有行政区划,进一步明确了具体的地区范围;街道的描述则让我们对周边环境有了更清晰的认知;门牌号更是精准地指向了具体的地点;而地址描述则以一种更为通俗易懂的方式将所有这些信息整合起来,为用户提供一个全面而直观的位置表达。这样丰富多样的信息呈现方式,无疑更加便于用户理解和把握自己所处的位置,无论是在日常的出行导航中,还是在社交应用里与朋友分享位置,都能让用户轻松便捷地知晓自己的具体方位,为我们的数字生活带来更多的便利和舒适体验。

查看地理编码与逆地理编码服务是否可用

首先,开发者在进行操作时,需要优先调用isGeoServiceAvailable方法来查询地理编码与逆地理编码服务的可用性。这一步骤至关重要,因为只有当确定服务可用的情况下,才能够进行后续的编码转化操作。如果经过查询发现服务不可用,那么就意味着该设备并不具备地理编码与逆地理编码转化能力。这种情况下,开发者务必不要使用相关接口,以免引起不必要的错误或者异常情况,从而确保应用程序的稳定性。

let isAvailable = geoLocationManager.isGeocoderAvailable();

把坐标转化为地理位置信息

在实际应用中,我们可以通过调用getCurrentLocation()函数获取当前位置,也可以使用on('locationChange')方法进行位置变化订阅。然而,通过这两种方式所获取到的位置信息都是以坐标形式呈现出来的,对于普通用户而言,这种坐标形式的位置信息可能会显得比较抽象且难以理解。

为了能够让用户更加直观地理解位置信息,开发者可以调用getAddressesFromLocation方法,该方法能够将坐标形式的位置信息转化为地理位置信息。比如国家信息、行政区、城市信息、区/县信息、路名等等。具体位置信息如以下类所示:

/**
 * 地理编码地址信息
 */
export interface GeoAddress {
    /**
     * 纬度信息,正值表示北纬,负值表示南纬。
     * 取值范围为[-90, 90],仅支持WGS84坐标系。
     */
    latitude?: number;
    /**
     * 经度信息,正值表示东经,负值表示西经。
     * 取值范围为[-180, 180],仅支持WGS84坐标系。
     */
    longitude?: number;
    /**
     * 位置描述信息的语言。
     * zh:中文;en:英文。
     */
    locale?: string;
    /**
     * 详细地址信息。
     */
    placeName?: string;
    /**
     * 国家码信息。
     */
    countryCode?: string;
    /**
     * 国家信息。
     */
    countryName?: string;
    /**
     * 一级行政区,一般是省/州。
     */
    administrativeArea?: string;
    /**
     * 二级行政区,一般是市。
     */
    subAdministrativeArea?: string;
    /**
     * 城市信息,一般是市。
     */
    locality?: string;
    /**
     * 子城市信息,一般是区/县。
     */
    subLocality?: string;
    /**
     * 路名信息。
     */
    roadName?: string;
    /**
     * 子路名信息。
     */
    subRoadName?: string;
    /**
     * 门牌号信息。
     */
    premises?: string;
    /**
     * 邮政编码信息。
     */
    postalCode?: string;
    /**
     * 联系方式信息。
     */
    phoneNumber?: string;
    /**
     * 位置信息附件的网址信息。
     */
    addressUrl?: string;
    /**
     * 附加的描述信息。
     * 目前包含城市编码cityCode和区划编码adminCode。
     */
    descriptions?: Array< string >;
    /**
     * 附加的描述信息数量。
     * 取值大于等于0,推荐该值小于10。
     */
    descriptionsSize?: number;
}

以转化当前坐标为例,代码如下所示:

/**
 * 逆地理编码请求参数
 */
export interface ReverseGeoCodeRequest {
    /**
     * 指定位置描述信息的语言。
     * zh:中文;en:英文。
     */
    locale?: string;
    /**
     * 限制查询结果在指定的国家区,采用ISO3166-1 alpha-2。
     * CN代表中国。
     */
    country?: string;
    /**
     * 纬度信息。
     */
    latitude: number;
    /**
     * 经度信息。
     */
    longitude: number;
    /**
     * 指定返回位置信息的最大个数。
     */
    maxItems?: number;
}

/**
 * 坐标转化为地理位置信息
 * @param latitude
 * @param longitude
 * @param maxItems
 * @returns
 */
static async getAddressesFromLocation(latitude: number,
  longitude: number, maxItems: number = 1): Promise< geoLocationManager.GeoAddress[] | undefined > {
  const request: geoLocationManager.ReverseGeoCodeRequest = {
    locale: "zh",
    country: "CN",
    latitude,
    longitude,
    maxItems
  };
  let location: geoLocationManager.GeoAddress[] | undefined = undefined;
  try {
    location = await geoLocationManager.getAddressesFromLocation(request);
    console.info(`[AppLogger]坐标转化为地理位置信息:${JSON.stringify(location)}`);
  } catch (error) {
    const err = error as BusinessError;
    console.error(`[AppLogger]坐标转化为地理位置信息异常:${JSON.stringify(err)}`);
  }
  return location;
}


Button('坐标转化为地理位置信息')
  .onClick(async () = > {
    this.location = await LocationUtil.getSingleLocationRequest(geoLocationManager.LocatingPriority.PRIORITY_LOCATING_SPEED);
    if (this.location !== undefined) {
      this.locationArr = await LocationUtil.getAddressesFromLocation(this.location?.latitude, this.location?.longitude);
    }
  })

位置服务

把地理位置信息转化为坐标

在导航类App的实际使用场景中,当用户进行位置搜索时,通常会输入具体的位置信息,比如某个商场的名称、某条街道的地址或者某个景点的具体描述等。但是,对于地图的显示而言,它所需要的是精确的位置坐标信息,只有这样才能够准确地在地图上进行标注和展示。

在这种情况下,为了实现从用户输入的位置描述到地图所需的坐标信息的转化,开发者可以调用getAddressesFromLocationName方法。这个方法就像是一座桥梁,能够将用户输入的直观的位置描述转化为地图能够识别和使用的位置坐标。通过这样的转化,不仅可以满足地图显示的需求,还能够为用户提供更加准确和便捷的导航服务,让用户能够更加轻松地找到自己想要达到的目的地。

以转化用户输入地理位置为例,代码如下所示:

/**
 * 地理编码请求参数
 */
export interface GeoCodeRequest {
    /**
     * 位置描述信息的语言。
     * zh:中文;en:英文。
     */
    locale?: string;
    /**
     * 限制查询结果在指定的国家区,采用ISO3166-1 alpha-2。
     * CN代表中国。
     */
    country?: string;
    /**
     * 位置信息描述。
     */
    description: string;
    /**
     * 返回结果信息的最大个数。
     */
    maxItems?: number;
    /**
     * 最小纬度信息。
     */
    minLatitude?: number;
    /**
     * 最小经度信息。
     */
    minLongitude?: number;
    /**
     * 最大纬度信息。
     */
    maxLatitude?: number;
    /**
     * 最大经度信息。
     */
    maxLongitude?: number;
}

/**
 * 地理位置转化为坐标信息
 * @param description
 * @param maxItems
 * @returns
 */
static async getAddressesFromLocationName(description: string,
  maxItems: number = 1): Promise< geoLocationManager.GeoAddress[] | undefined > {
  const request: geoLocationManager.GeoCodeRequest = {
    description,
    maxItems
  };
  let location: geoLocationManager.GeoAddress[] | undefined = undefined;
  try {
    location = await geoLocationManager.getAddressesFromLocationName(request);
    console.info(`[AppLogger]地理位置转化为坐标信息:${JSON.stringify(location)}`);
  } catch (error) {
    const err = error as BusinessError;
    console.error(`[AppLogger]地理位置转化为坐标信息异常:${JSON.stringify(err)}`);
  }
  return location;
}

TextInput({ placeholder: "请输入具体的位置信息..." })
  .onChange((value: string) = > {
    this.val = value;
  })
Button('坐标转化为地理位置信息')
  .onClick(async () = > {
    if (LocationUtil.usedGeocoderAvailable()) {
      this.locationArr = await LocationUtil.getAddressesFromLocationName(this.val, 5);
    }
  })

位置服务

使用ForEach渲染列表数据

List() {
  ForEach(this.locationArr, (item: geoLocationManager.GeoAddress) = > {
    ListItem() {
      Column({ space: 8 }) {
        Text(item.placeName)
          .fontSize(16)
        Text(`坐标:[${item.latitude}, ${item.longitude}]`)
          .fontSize(12)
        Text(`${item.countryName} ${item.administrativeArea} ${item.locality} ${item.subLocality} ${item.roadName} ${item.subRoadName}`)
          .fontSize(12)
      }
      .width('100%')
      .padding(12)
      .backgroundColor(0xF1F3F5)
      .borderRadius(8)
      .justifyContent(FlexAlign.Start)
    }
  })
}
.width('90%')
.divider({
  strokeWidth: 4,
  color: 0xFFFFFF
})

位置服务

审核编辑 黄宇

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分