鸿蒙 ArkUI实现地图找房效果

常用的地图找房功能,是在地图上添加区域、商圈、房源等一些自定义 marker,然后配上自己应用的一些筛选逻辑构成,在这里使用鸿蒙 ArkUI 简单实现下怎么添加区域/商圈、房源等 Marker.

1、开启地图服务

在华为开发者官网,注册应用,然后在我的项目-我的应用-ApI管理中开启地图服务Map Kit;

2、地图相关配置

在工程中entry模块的module.json5文件中配置client_id,client_id可以在 项目设置 > 常规 > 应用中找到,这里可能需要配置公钥指纹,具体可以参考开发者官网

复制代码
"module": {
  "name": "xxxx",
  "type": "entry",
  "description": "xxxx",
  "mainElement": "xxxx",
  "deviceTypes": [
    'phone',
  'tablet'
  ],
  "pages": "xxxx",
  "abilities": [],
  "metadata": [
    {
      "name": "client_id",
      "value": "xxxxxx"  // 配置为获取的Client ID
    }
  ]
}

3、创建地图

使用MapComponent组件创建地图,需要传递两个参数mapOptions和mapCallback,需要重写onPageShow和onPageHide两个生命周期方法,用来显示和隐藏地图。如果地图不显示的话,可以参考官网的地图不显示

复制代码
MapComponent(mapOptions: mapCommon.MapOptions, mapCallback: AsyncCallback<map.MapComponentController>)

// 地图初始化参数,设置地图中心点坐标及层级
    this.mapOptions = {
      position: {
        target: {
          latitude: 39.9,
          longitude: 116.4
        },
        zoom: 10
      }
    };

    // 地图初始化的回调
    this.callback = async (err, mapController) => {
      if (!err) {
        // 获取地图的控制器类,用来操作地图
        this.mapController = mapController;
        this.mapEventManager = this.mapController.getEventManager();
        let callback = () => {
          console.info(this.TAG, `on-mapLoad`);
        }
        this.mapEventManager.on("mapLoad", callback);
      }
    };
  }

 // 页面每次显示时触发一次,包括路由过程、应用进入前台等场景,仅@Entry装饰的自定义组件生效
  onPageShow(): void {
    // 将地图切换到前台
    if (this.mapController) {
      this.mapController.show();
    }
  }

  // 页面每次隐藏时触发一次,包括路由过程、应用进入后台等场景,仅@Entry装饰的自定义组件生效
  onPageHide(): void {
    // 将地图切换到后台
    if (this.mapController) {
      this.mapController.hide();
    }
  }

  build() {
    Stack() {
      // 调用MapComponent组件初始化地图
      MapComponent({ mapOptions: this.mapOptions, mapCallback: this.callback }).width('100%').height('100%');
    }.height('100%')
  }

4、地图上显示我的位置图标

需要先动态申请定位权限,获取具体定位坐标后,通过地图操作类mapController调用setMyLocation方法设置定位坐标,animateCamera方法移动地图到定位坐标位置,可以设置缩放等级,这样就可以在地图上显示一个位置图标;

复制代码
static LocationPermissions: Array<Permissions> =
    ['ohos.permission.LOCATION', 'ohos.permission.APPROXIMATELY_LOCATION'];

//开始定位
  startLocation() {
    //申请定位权限
    AgentUtil.requestPermissions(AgentUtil.LocationPermissions, async () => {
      //获取到定位权限
      // 启用我的位置图层,mapController为地图操作类对象,获取方式详见显示地图章节
      this.mapController?.setMyLocationEnabled(true);
      // 启用我的位置按钮
      this.mapController?.setMyLocationControlsEnabled(true);

      // 获取用户位置坐标
      let location = await geoLocationManager.getCurrentLocation()
      // 转换经纬度坐标
      // let wgs84LatLng = AgentUtil.wgs84LatLng(location.latitude, location.longitude)
      // location.latitude = wgs84LatLng.latitude
      // location.longitude = wgs84LatLng.longitude
      // 设置用户的位置
      this.mapController?.setMyLocation(location);

      setTimeout(() => {
        //移动地图到目标位置
        this.mapController?.animateCamera(map.newLatLng(location, 15))
      }, 100)
    })
  }

5、监听地图停止移动

当地图移动到定位坐标后,可以通过mapController.on("cameraIdle", () => {})方法,监听地图停止移动,在回调中可以做后续展示 Marker的逻辑;这里根据地图缩放等级来区分展示区域或者楼盘,后续可以继续完善,添加商圈层级,一级自己需要的业务逻辑。

复制代码
 this.mapEventManager.on("cameraIdle", () => {
          //地图停止移动,可以执行一些操作
          let position = this.mapController?.getCameraPosition()
          let currentZoom = position?.zoom ?? 0
          if (currentZoom < 14) {
            //展示区域商圈
            this.addAreaMarkers()
          }else{
            //展示房源楼盘
            this.addHouseMarkers()

          }
        });

6、自定义 Marker

1. 自定义圆形 Marker

比如可以用来显示区域和商圈,由于 Map Kit 中添加的 Marker的时候并不支持自定义样式,只支持设置图标 icon,所以这里先使用 Build自定义组件,绘制出圆形 Marker:

复制代码
  @Builder
  BuilderMapCircularLabel(text: string, id: string) {
    Stack() {
      //绘制圆形背景
      Circle({ width: 70, height: 70 })
        .shadow({ radius: 8 })
        .fill($r("app.color.main_color"))
      Text(text)
        .fontSize(12)
        .fontColor($r("app.color.white"))
        .textAlign(TextAlign.Center)
        .padding({
          left: 4,
          right: 4,
        })
    }.id(id)
  }
2. 自定义房源展示 Marker

背景底部小三角,可以使用 Path 路径绘制。

复制代码
/**
   * 矩形带小三角标的 marker 标注
   * @param text
   */
  @Builder
  BuilderMapRectLabel(text: string, id: string) {
    Column() {
      Text(text)
        .fontSize(14)
        .fontColor($r("app.color.white"))
        .backgroundColor($r("app.color.main_color"))
        .shadow({ radius: 5, color: $r("app.color.white") })
        .borderRadius(14)
        .padding({
          left: 15,
          right: 15,
          top: 4,
          bottom: 4
        })
      //根据路径绘制小三角形
      Path()
        .width(12)
        .height(6)
        .commands('M0 0 L30 0 L15 15 Z')
        .fill($r("app.color.main_color"))
        .strokeWidth(0)
    }.id(id).alignItems(HorizontalAlign.Center)
  }

7、地图上展示自定义 Marker

使用截屏类componentSnapshot,调用将自定义组件生成快照的方法createFromBuilder,在回调中获取生成的PixelMap对象,将 PixelMap对象设置给 MarkerOptions Marker参数icon中,调用 addMarker 方法在地图上生成 Marker点.

复制代码
componentSnapshot.createFromBuilder(() => {
      //要生成图片 PixelMap对象的自定义组件
      this.BuilderMapRectLabel(text, houseId)
    }, async (error, imagePixelMap) => {
      if (error) {
        LogUtil.debug("snapshot failure: " + JSON.stringify(error));
        return
      }

      let markerOptions: mapCommon.MarkerOptions = {
        position: latLng,
        icon: imagePixelMap, //生成 PixelMap后的自定义组件
        title: houseId,  //可以传一些自定义参数,跟组件进行绑定,方便后续点击进行操作
      }
      if (!this.rectMarkers.find(marker => marker.getTitle() == houseId)) {
        //如果marker集合不存在已添加的 marker,则添加marker
        let marker = await this.mapController?.addMarker(markerOptions)
        marker?.setClickable(true)
        if (marker) {
          this.rectMarkers.push(marker)
        }
      }
    })

8、监听 Marker的点击事件

使用 mapEventManager 的 mapEventManager.on("markerClick", () => {})方法来监听 marker的点击事件,在点击事件回调中根据地图层级可以处理点击的业务逻辑,比如点击进入地图层级,展示楼盘 marker等。

复制代码
 this.mapEventManager.on("markerClick", (marker) => {
          if (marker.getTitle().length == 2) {
            //点击区域商圈,进入房源层级,展示房源信息
            //移动地图到目标位置
            this.mapController?.animateCamera(map.newLatLng({
              latitude: 30.513746,
              longitude: 114.403009
            }, 15))
          } else {
            //点击房源,可以进行后续操作
            ToastUtil.showToast(marker?.getTitle())
          }
        })

总结

以上就是鸿蒙 ArkUI实现地图找房的基本流程,具体细节可以根据自己的业务需求,实现自己想要的效果。目前地图上的制定 marker 还是通过自定义组件生成图片,来展示,当Marker比较多时,对性能可能有一定的影响,可以进一步优化,每次只展示当前屏幕内的 Marker图,滑动移除屏幕外的 marker,同时记录已经生成的 marker,避免每次都要重新生成 marker PixelMap对象。

相关推荐
灏瀚星空几秒前
基于Python的量化交易实盘部署与风险管理指南
开发语言·python
Run_Teenage6 分钟前
C++类和对象:运行符重载、取地址运算符重载、const 修饰的类如何作为参数
开发语言·c++
一只小bit7 分钟前
More Effective C++:改善编程与设计(上)
开发语言·c++·方法·技巧
钢铁男儿1 小时前
C# 方法(栈帧)
开发语言·c#
忆源3 小时前
【Qt】之音视频编程1:QtAV的背景和安装篇
开发语言·qt·音视频
敲键盘的小夜猫3 小时前
Python核心数据类型全解析:字符串、列表、元组、字典与集合
开发语言·python
特立独行的猫a3 小时前
HarmonyOS 【诗韵悠然】AI古诗词赏析APP开发实战从零到一系列(一、开篇,项目介绍)
人工智能·华为·harmonyos·古诗词
李匠20243 小时前
C++GO语言微服务之图片、短信验证码生成及存储
开发语言·c++·微服务·golang
巨龙之路6 小时前
C语言中的assert
c语言·开发语言
2301_776681657 小时前
【用「概率思维」重新理解生活】
开发语言·人工智能·自然语言处理