博客 / 詳情

返回

HarmonyOS Next 實現地圖找房功能

常用的地圖找房功能,是在地圖上添加區域、商圈、房源等一些自定義 marker,然後配上自己應用的一些篩選邏輯構成,在這裏使用鴻蒙 ArkUI 簡單實現下怎麼添加區域/商圈、房源等 Marker.

1741434400992.png

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對象。

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.