expo-gaode-map 2.2.38 → 2.2.40-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/build.gradle +6 -31
- package/android/src/main/java/expo/modules/gaodemap/ExpoGaodeMapView.kt +35 -12
- package/android/src/main/java/expo/modules/gaodemap/ExpoGaodeMapViewModule.kt +2 -0
- package/android/src/main/java/expo/modules/gaodemap/managers/UIManager.kt +8 -0
- package/android/src/main/java/expo/modules/gaodemap/overlays/MarkerView.kt +48 -7
- package/build/ExpoGaodeMapOfflineModule.js +1 -1
- package/build/ExpoGaodeMapOfflineModule.js.map +1 -1
- package/build/ExpoGaodeMapView.js +2 -8
- package/build/ExpoGaodeMapView.js.map +1 -1
- package/build/components/AreaMaskOverlay.d.ts +1 -2
- package/build/components/AreaMaskOverlay.d.ts.map +1 -1
- package/build/components/AreaMaskOverlay.js +2 -1
- package/build/components/AreaMaskOverlay.js.map +1 -1
- package/build/components/FoldableMapView.d.ts +3 -2
- package/build/components/FoldableMapView.d.ts.map +1 -1
- package/build/components/FoldableMapView.js +2 -1
- package/build/components/FoldableMapView.js.map +1 -1
- package/build/components/MapUI.js +2 -1
- package/build/components/MapUI.js.map +1 -1
- package/build/components/RouteOverlay.d.ts +1 -2
- package/build/components/RouteOverlay.d.ts.map +1 -1
- package/build/components/RouteOverlay.js +5 -5
- package/build/components/RouteOverlay.js.map +1 -1
- package/build/components/overlays/Circle.d.ts +1 -1
- package/build/components/overlays/Circle.d.ts.map +1 -1
- package/build/components/overlays/Circle.js +2 -1
- package/build/components/overlays/Circle.js.map +1 -1
- package/build/components/overlays/Cluster.d.ts +1 -1
- package/build/components/overlays/Cluster.d.ts.map +1 -1
- package/build/components/overlays/Cluster.js +2 -1
- package/build/components/overlays/Cluster.js.map +1 -1
- package/build/components/overlays/HeatMap.d.ts +1 -1
- package/build/components/overlays/HeatMap.d.ts.map +1 -1
- package/build/components/overlays/HeatMap.js +2 -1
- package/build/components/overlays/HeatMap.js.map +1 -1
- package/build/components/overlays/Marker.d.ts +1 -1
- package/build/components/overlays/Marker.d.ts.map +1 -1
- package/build/components/overlays/Marker.js +8 -7
- package/build/components/overlays/Marker.js.map +1 -1
- package/build/components/overlays/MultiPoint.d.ts +1 -2
- package/build/components/overlays/MultiPoint.d.ts.map +1 -1
- package/build/components/overlays/MultiPoint.js +2 -1
- package/build/components/overlays/MultiPoint.js.map +1 -1
- package/build/components/overlays/Polygon.d.ts +1 -1
- package/build/components/overlays/Polygon.d.ts.map +1 -1
- package/build/components/overlays/Polygon.js +2 -1
- package/build/components/overlays/Polygon.js.map +1 -1
- package/build/components/overlays/Polyline.d.ts +1 -1
- package/build/components/overlays/Polyline.d.ts.map +1 -1
- package/build/components/overlays/Polyline.js +2 -1
- package/build/components/overlays/Polyline.js.map +1 -1
- package/build/module/geometry.d.ts.map +1 -1
- package/build/module/geometry.js +2 -1
- package/build/module/geometry.js.map +1 -1
- package/build/search/ExpoGaodeMapSearchModule.d.ts +1 -1
- package/build/search/ExpoGaodeMapSearchModule.d.ts.map +1 -1
- package/build/search/ExpoGaodeMapSearchModule.js.map +1 -1
- package/build/types/common.types.d.ts +1 -1
- package/build/types/common.types.d.ts.map +1 -1
- package/build/types/common.types.js.map +1 -1
- package/build/types/index.d.ts +1 -1
- package/build/types/index.d.ts.map +1 -1
- package/build/types/index.js.map +1 -1
- package/build/types/map-view.types.d.ts +13 -2
- package/build/types/map-view.types.d.ts.map +1 -1
- package/build/types/map-view.types.js.map +1 -1
- package/build/utils/GeoUtils.d.ts +2 -2
- package/build/utils/GeoUtils.d.ts.map +1 -1
- package/build/utils/GeoUtils.js +3 -3
- package/build/utils/GeoUtils.js.map +1 -1
- package/build/utils/RouteUtils.d.ts.map +1 -1
- package/build/utils/RouteUtils.js +5 -2
- package/build/utils/RouteUtils.js.map +1 -1
- package/ios/ExpoGaodeMapView.swift +251 -13
- package/ios/ExpoGaodeMapViewModule.swift +5 -0
- package/ios/managers/UIManager.swift +3 -0
- package/ios/overlays/MarkerView.swift +205 -38
- package/package.json +9 -7
- package/plugin/build/withGaodeMap.js +3 -2
|
@@ -28,6 +28,12 @@ class ExpoGaodeMapView: ExpoView, MAMapViewDelegate, UIGestureRecognizerDelegate
|
|
|
28
28
|
var showsScale: Bool = true
|
|
29
29
|
/// 是否启用缩放手势
|
|
30
30
|
var isZoomEnabled: Bool = true
|
|
31
|
+
/// 缩放手势锚点:gesture 跟随手势中心点;center 固定地图中心点
|
|
32
|
+
var zoomGestureAnchor: String = "gesture" {
|
|
33
|
+
didSet {
|
|
34
|
+
applyZoomGestureSettings()
|
|
35
|
+
}
|
|
36
|
+
}
|
|
31
37
|
/// 是否启用滚动手势
|
|
32
38
|
var isScrollEnabled: Bool = true
|
|
33
39
|
/// 是否启用旋转手势
|
|
@@ -96,6 +102,8 @@ class ExpoGaodeMapView: ExpoView, MAMapViewDelegate, UIGestureRecognizerDelegate
|
|
|
96
102
|
private var uiManager: UIManager!
|
|
97
103
|
/// 地图是否已加载完成
|
|
98
104
|
private var isMapLoaded = false
|
|
105
|
+
/// 定位 annotation 首次出现后是否已补应用定位样式
|
|
106
|
+
private var hasAppliedUserLocationStyleAfterLocationUpdate = false
|
|
99
107
|
/// 初始相机是否已应用(仅应用一次,避免与运行时相机控制冲突)
|
|
100
108
|
private var hasAppliedInitialCameraPosition = false
|
|
101
109
|
/// 是否正在处理 annotation 选择事件
|
|
@@ -113,9 +121,15 @@ class ExpoGaodeMapView: ExpoView, MAMapViewDelegate, UIGestureRecognizerDelegate
|
|
|
113
121
|
private var pendingCameraMoveData: [String: Any]?
|
|
114
122
|
private var cameraMoveDispatchWorkItem: DispatchWorkItem?
|
|
115
123
|
private var lastCameraMoveDispatchTime: CFTimeInterval = 0
|
|
124
|
+
/// iOS 缩放惯性/连续 setZoom 可能多次触发 regionDidChange,合并后再派发 idle。
|
|
125
|
+
private var pendingCameraIdleData: [String: Any]?
|
|
126
|
+
private var cameraIdleDispatchWorkItem: DispatchWorkItem?
|
|
127
|
+
private let cameraIdleDebounceMs = 160
|
|
116
128
|
|
|
117
129
|
/// 缩放手势识别器(用于模拟惯性)
|
|
118
130
|
private var pinchGesture: UIPinchGestureRecognizer!
|
|
131
|
+
private var centerAnchoredPinchStartZoom: CGFloat?
|
|
132
|
+
private var centerAnchoredZoomCoordinate: CLLocationCoordinate2D?
|
|
119
133
|
|
|
120
134
|
// 惯性动画相关属性
|
|
121
135
|
private var displayLink: CADisplayLink?
|
|
@@ -361,12 +375,12 @@ class ExpoGaodeMapView: ExpoView, MAMapViewDelegate, UIGestureRecognizerDelegate
|
|
|
361
375
|
uiManager.setMapType(1)
|
|
362
376
|
uiManager.setShowsScale(showsScale)
|
|
363
377
|
uiManager.setShowsCompass(showsCompass)
|
|
364
|
-
|
|
378
|
+
applyZoomGestureSettings()
|
|
365
379
|
uiManager.setScrollEnabled(isScrollEnabled)
|
|
366
380
|
uiManager.setRotateEnabled(isRotateEnabled)
|
|
367
381
|
uiManager.setTiltEnabled(isTiltEnabled)
|
|
368
382
|
uiManager.setShowsUserLocation(showsUserLocation, followUser: followUserLocation)
|
|
369
|
-
|
|
383
|
+
applyUserLocationStyle()
|
|
370
384
|
}
|
|
371
385
|
|
|
372
386
|
/**
|
|
@@ -390,21 +404,21 @@ class ExpoGaodeMapView: ExpoView, MAMapViewDelegate, UIGestureRecognizerDelegate
|
|
|
390
404
|
|
|
391
405
|
uiManager.setShowsScale(showsScale)
|
|
392
406
|
uiManager.setShowsCompass(showsCompass)
|
|
393
|
-
|
|
407
|
+
applyZoomGestureSettings()
|
|
394
408
|
uiManager.setScrollEnabled(isScrollEnabled)
|
|
395
409
|
uiManager.setRotateEnabled(isRotateEnabled)
|
|
396
410
|
uiManager.setTiltEnabled(isTiltEnabled)
|
|
397
411
|
uiManager.setShowsUserLocation(showsUserLocation, followUser: followUserLocation)
|
|
412
|
+
applyUserLocationStyle()
|
|
398
413
|
uiManager.setShowsTraffic(showsTraffic)
|
|
399
414
|
uiManager.setShowsBuildings(showsBuildings)
|
|
400
415
|
uiManager.setShowsIndoorMap(showsIndoorMap)
|
|
401
|
-
updatePinchGestureState()
|
|
402
416
|
mapView.distanceFilter = distanceFilter
|
|
403
417
|
mapView.headingFilter = headingFilter
|
|
404
418
|
if let customMapStyleData {
|
|
405
419
|
uiManager.setCustomMapStyle(customMapStyleData)
|
|
406
420
|
}
|
|
407
|
-
|
|
421
|
+
|
|
408
422
|
// 更新苹果地图样式
|
|
409
423
|
updateAppleMapStyle()
|
|
410
424
|
|
|
@@ -439,6 +453,13 @@ class ExpoGaodeMapView: ExpoView, MAMapViewDelegate, UIGestureRecognizerDelegate
|
|
|
439
453
|
// MARK: - 手势处理
|
|
440
454
|
|
|
441
455
|
@objc func handlePinch(_ gesture: UIPinchGestureRecognizer) {
|
|
456
|
+
guard isZoomEnabled else { return }
|
|
457
|
+
|
|
458
|
+
if zoomGestureAnchor == "center" {
|
|
459
|
+
handleCenterAnchoredPinch(gesture)
|
|
460
|
+
return
|
|
461
|
+
}
|
|
462
|
+
|
|
442
463
|
if gesture.state == .began {
|
|
443
464
|
// 手势开始,立即停止之前的惯性动画,避免冲突
|
|
444
465
|
stopInertiaAnimation()
|
|
@@ -455,6 +476,44 @@ class ExpoGaodeMapView: ExpoView, MAMapViewDelegate, UIGestureRecognizerDelegate
|
|
|
455
476
|
}
|
|
456
477
|
}
|
|
457
478
|
}
|
|
479
|
+
|
|
480
|
+
private func handleCenterAnchoredPinch(_ gesture: UIPinchGestureRecognizer) {
|
|
481
|
+
switch gesture.state {
|
|
482
|
+
case .began:
|
|
483
|
+
stopInertiaAnimation()
|
|
484
|
+
centerAnchoredPinchStartZoom = mapView.zoomLevel
|
|
485
|
+
centerAnchoredZoomCoordinate = mapView.centerCoordinate
|
|
486
|
+
case .changed:
|
|
487
|
+
let startZoom = centerAnchoredPinchStartZoom ?? mapView.zoomLevel
|
|
488
|
+
let center = centerAnchoredZoomCoordinate ?? mapView.centerCoordinate
|
|
489
|
+
let zoomDelta = log2(Double(max(gesture.scale, 0.0001)))
|
|
490
|
+
applyCenterAnchoredZoom(CGFloat(Double(startZoom) + zoomDelta), center: center)
|
|
491
|
+
case .ended, .cancelled, .failed:
|
|
492
|
+
centerAnchoredPinchStartZoom = nil
|
|
493
|
+
let velocity = gesture.velocity
|
|
494
|
+
if abs(velocity) > 0.1 {
|
|
495
|
+
zoomVelocity = Double(velocity) * 0.02
|
|
496
|
+
if centerAnchoredZoomCoordinate == nil {
|
|
497
|
+
centerAnchoredZoomCoordinate = mapView.centerCoordinate
|
|
498
|
+
}
|
|
499
|
+
startInertiaAnimation()
|
|
500
|
+
} else {
|
|
501
|
+
centerAnchoredZoomCoordinate = nil
|
|
502
|
+
}
|
|
503
|
+
default:
|
|
504
|
+
break
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
private func applyCenterAnchoredZoom(_ zoom: CGFloat, center: CLLocationCoordinate2D) {
|
|
509
|
+
let validZoom = max(mapView.minZoomLevel, min(mapView.maxZoomLevel, zoom))
|
|
510
|
+
let status = MAMapStatus()
|
|
511
|
+
status.centerCoordinate = center
|
|
512
|
+
status.zoomLevel = validZoom
|
|
513
|
+
status.rotationDegree = mapView.rotationDegree
|
|
514
|
+
status.cameraDegree = mapView.cameraDegree
|
|
515
|
+
mapView.setMapStatus(status, animated: false, duration: 0)
|
|
516
|
+
}
|
|
458
517
|
|
|
459
518
|
private func startInertiaAnimation() {
|
|
460
519
|
stopInertiaAnimation()
|
|
@@ -476,12 +535,21 @@ class ExpoGaodeMapView: ExpoView, MAMapViewDelegate, UIGestureRecognizerDelegate
|
|
|
476
535
|
// 碰到边界,停止动画
|
|
477
536
|
newZoom = max(mapView.minZoomLevel, min(mapView.maxZoomLevel, newZoom))
|
|
478
537
|
stopInertiaAnimation()
|
|
479
|
-
|
|
538
|
+
if zoomGestureAnchor == "center" {
|
|
539
|
+
applyCenterAnchoredZoom(newZoom, center: centerAnchoredZoomCoordinate ?? mapView.centerCoordinate)
|
|
540
|
+
centerAnchoredZoomCoordinate = nil
|
|
541
|
+
} else {
|
|
542
|
+
mapView.setZoomLevel(newZoom, animated: false)
|
|
543
|
+
}
|
|
480
544
|
return
|
|
481
545
|
}
|
|
482
546
|
|
|
483
547
|
// 更新地图缩放级别(animated: false 以保证逐帧控制的流畅性)
|
|
484
|
-
|
|
548
|
+
if zoomGestureAnchor == "center" {
|
|
549
|
+
applyCenterAnchoredZoom(newZoom, center: centerAnchoredZoomCoordinate ?? mapView.centerCoordinate)
|
|
550
|
+
} else {
|
|
551
|
+
mapView.setZoomLevel(newZoom, animated: false)
|
|
552
|
+
}
|
|
485
553
|
|
|
486
554
|
// 减速(应用摩擦力)
|
|
487
555
|
zoomVelocity *= friction
|
|
@@ -489,6 +557,7 @@ class ExpoGaodeMapView: ExpoView, MAMapViewDelegate, UIGestureRecognizerDelegate
|
|
|
489
557
|
// 停止条件
|
|
490
558
|
if abs(zoomVelocity) < velocityThreshold {
|
|
491
559
|
stopInertiaAnimation()
|
|
560
|
+
centerAnchoredZoomCoordinate = nil
|
|
492
561
|
}
|
|
493
562
|
}
|
|
494
563
|
|
|
@@ -568,6 +637,9 @@ class ExpoGaodeMapView: ExpoView, MAMapViewDelegate, UIGestureRecognizerDelegate
|
|
|
568
637
|
func setFollowUserLocation(_ follow: Bool) {
|
|
569
638
|
followUserLocation = follow
|
|
570
639
|
uiManager?.setShowsUserLocation(showsUserLocation, followUser: follow)
|
|
640
|
+
if showsUserLocation {
|
|
641
|
+
applyUserLocationStyle()
|
|
642
|
+
}
|
|
571
643
|
}
|
|
572
644
|
|
|
573
645
|
func setShowsUserLocation(_ show: Bool) {
|
|
@@ -580,6 +652,7 @@ class ExpoGaodeMapView: ExpoView, MAMapViewDelegate, UIGestureRecognizerDelegate
|
|
|
580
652
|
|
|
581
653
|
func setUserLocationRepresentation(_ config: [String: Any]) {
|
|
582
654
|
userLocationRepresentation = config
|
|
655
|
+
hasAppliedUserLocationStyleAfterLocationUpdate = false
|
|
583
656
|
if showsUserLocation {
|
|
584
657
|
uiManager?.setUserLocationRepresentation(config)
|
|
585
658
|
}
|
|
@@ -589,7 +662,7 @@ class ExpoGaodeMapView: ExpoView, MAMapViewDelegate, UIGestureRecognizerDelegate
|
|
|
589
662
|
* 应用用户位置样式
|
|
590
663
|
*/
|
|
591
664
|
private func applyUserLocationStyle() {
|
|
592
|
-
guard let config = userLocationRepresentation else { return }
|
|
665
|
+
guard showsUserLocation, let config = userLocationRepresentation else { return }
|
|
593
666
|
uiManager?.setUserLocationRepresentation(config)
|
|
594
667
|
}
|
|
595
668
|
|
|
@@ -806,6 +879,9 @@ class ExpoGaodeMapView: ExpoView, MAMapViewDelegate, UIGestureRecognizerDelegate
|
|
|
806
879
|
pendingCameraMoveData = nil
|
|
807
880
|
cameraMoveDispatchWorkItem?.cancel()
|
|
808
881
|
cameraMoveDispatchWorkItem = nil
|
|
882
|
+
pendingCameraIdleData = nil
|
|
883
|
+
cameraIdleDispatchWorkItem?.cancel()
|
|
884
|
+
cameraIdleDispatchWorkItem = nil
|
|
809
885
|
if let privacyObserver {
|
|
810
886
|
NotificationCenter.default.removeObserver(privacyObserver)
|
|
811
887
|
}
|
|
@@ -861,6 +937,7 @@ class ExpoGaodeMapView: ExpoView, MAMapViewDelegate, UIGestureRecognizerDelegate
|
|
|
861
937
|
super.addSubview(resolvedMapView)
|
|
862
938
|
isMapLoaded = false
|
|
863
939
|
hasAppliedInitialCameraPosition = false
|
|
940
|
+
hasAppliedUserLocationStyleAfterLocationUpdate = false
|
|
864
941
|
|
|
865
942
|
cameraManager = CameraManager(mapView: resolvedMapView)
|
|
866
943
|
uiManager = UIManager(mapView: resolvedMapView)
|
|
@@ -879,13 +956,20 @@ class ExpoGaodeMapView: ExpoView, MAMapViewDelegate, UIGestureRecognizerDelegate
|
|
|
879
956
|
pinchGesture.delegate = self
|
|
880
957
|
resolvedMapView.addGestureRecognizer(pinchGesture)
|
|
881
958
|
self.pinchGesture = pinchGesture
|
|
882
|
-
|
|
959
|
+
applyZoomGestureSettings()
|
|
883
960
|
}
|
|
884
961
|
|
|
885
|
-
private func
|
|
962
|
+
private func applyZoomGestureSettings() {
|
|
963
|
+
uiManager?.setZoomEnabled(isZoomEnabled && zoomGestureAnchor != "center")
|
|
886
964
|
pinchGesture?.isEnabled = isZoomEnabled
|
|
965
|
+
if zoomGestureAnchor != "center" {
|
|
966
|
+
centerAnchoredPinchStartZoom = nil
|
|
967
|
+
centerAnchoredZoomCoordinate = nil
|
|
968
|
+
}
|
|
887
969
|
if !isZoomEnabled {
|
|
888
970
|
stopInertiaAnimation()
|
|
971
|
+
centerAnchoredPinchStartZoom = nil
|
|
972
|
+
centerAnchoredZoomCoordinate = nil
|
|
889
973
|
}
|
|
890
974
|
}
|
|
891
975
|
}
|
|
@@ -937,9 +1021,37 @@ extension ExpoGaodeMapView {
|
|
|
937
1021
|
if let styleData = customMapStyleData {
|
|
938
1022
|
uiManager?.setCustomMapStyle(styleData)
|
|
939
1023
|
}
|
|
1024
|
+
|
|
1025
|
+
applyUserLocationStyle()
|
|
940
1026
|
|
|
941
1027
|
onLoad(["loaded": true])
|
|
942
1028
|
}
|
|
1029
|
+
|
|
1030
|
+
/**
|
|
1031
|
+
* 定位更新回调
|
|
1032
|
+
*/
|
|
1033
|
+
public func mapView(_ mapView: MAMapView, didUpdate userLocation: MAUserLocation, updatingLocation: Bool) {
|
|
1034
|
+
guard updatingLocation, let location = userLocation.location else { return }
|
|
1035
|
+
|
|
1036
|
+
if !hasAppliedUserLocationStyleAfterLocationUpdate {
|
|
1037
|
+
applyUserLocationStyle()
|
|
1038
|
+
hasAppliedUserLocationStyleAfterLocationUpdate = true
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
let latitude = location.coordinate.latitude
|
|
1042
|
+
let longitude = location.coordinate.longitude
|
|
1043
|
+
guard latitude >= -90 && latitude <= 90,
|
|
1044
|
+
longitude >= -180 && longitude <= 180 else {
|
|
1045
|
+
return
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
onLocation([
|
|
1049
|
+
"latitude": latitude,
|
|
1050
|
+
"longitude": longitude,
|
|
1051
|
+
"accuracy": location.horizontalAccuracy,
|
|
1052
|
+
"timestamp": Date().timeIntervalSince1970 * 1000
|
|
1053
|
+
])
|
|
1054
|
+
}
|
|
943
1055
|
|
|
944
1056
|
/**
|
|
945
1057
|
* 地图区域即将改变时触发
|
|
@@ -958,7 +1070,7 @@ extension ExpoGaodeMapView {
|
|
|
958
1070
|
*/
|
|
959
1071
|
public func mapView(_ mapView: MAMapView, regionDidChangeAnimated animated: Bool) {
|
|
960
1072
|
flushPendingCameraMoveEvent()
|
|
961
|
-
|
|
1073
|
+
scheduleCameraIdleEvent(buildCameraEventData(for: mapView))
|
|
962
1074
|
|
|
963
1075
|
// 这里的 overlayViews 是 [UIView] 类型,可能包含 ClusterView
|
|
964
1076
|
for view in overlayViews {
|
|
@@ -1038,6 +1150,27 @@ extension ExpoGaodeMapView {
|
|
|
1038
1150
|
lastCameraMoveDispatchTime = timestamp
|
|
1039
1151
|
onCameraMove(eventData)
|
|
1040
1152
|
}
|
|
1153
|
+
|
|
1154
|
+
private func scheduleCameraIdleEvent(_ eventData: [String: Any]) {
|
|
1155
|
+
pendingCameraIdleData = eventData
|
|
1156
|
+
cameraIdleDispatchWorkItem?.cancel()
|
|
1157
|
+
|
|
1158
|
+
let workItem = DispatchWorkItem { [weak self] in
|
|
1159
|
+
guard let self = self, let latestEventData = self.pendingCameraIdleData else {
|
|
1160
|
+
return
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
self.pendingCameraIdleData = nil
|
|
1164
|
+
self.cameraIdleDispatchWorkItem = nil
|
|
1165
|
+
self.onCameraIdle(latestEventData)
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
cameraIdleDispatchWorkItem = workItem
|
|
1169
|
+
DispatchQueue.main.asyncAfter(
|
|
1170
|
+
deadline: .now() + Double(cameraIdleDebounceMs) / 1000.0,
|
|
1171
|
+
execute: workItem
|
|
1172
|
+
)
|
|
1173
|
+
}
|
|
1041
1174
|
|
|
1042
1175
|
/**
|
|
1043
1176
|
* 地图单击事件
|
|
@@ -1262,13 +1395,118 @@ extension ExpoGaodeMapView {
|
|
|
1262
1395
|
handleGaodePoiTouch(pois)
|
|
1263
1396
|
}
|
|
1264
1397
|
|
|
1398
|
+
private func getUserLocationAnnotationView(for mapView: MAMapView, annotation: MAAnnotation) -> MAAnnotationView? {
|
|
1399
|
+
guard let config = userLocationRepresentation,
|
|
1400
|
+
let imagePath = config["image"] as? String,
|
|
1401
|
+
!imagePath.isEmpty else {
|
|
1402
|
+
return nil
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
let reuseId = "ExpoGaodeMapUserLocationStyleReuseIdentifier"
|
|
1406
|
+
let annotationView: MAAnnotationView
|
|
1407
|
+
if let reusableView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseId) {
|
|
1408
|
+
annotationView = reusableView
|
|
1409
|
+
} else {
|
|
1410
|
+
annotationView = MAAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
|
|
1411
|
+
}
|
|
1412
|
+
annotationView.annotation = annotation
|
|
1413
|
+
annotationView.canShowCallout = false
|
|
1414
|
+
|
|
1415
|
+
let imageWidth = config["imageWidth"] as? Double
|
|
1416
|
+
let imageHeight = config["imageHeight"] as? Double
|
|
1417
|
+
let cacheKey = userLocationImageCacheKey(imagePath: imagePath, imageWidth: imageWidth, imageHeight: imageHeight)
|
|
1418
|
+
annotationView.accessibilityIdentifier = cacheKey
|
|
1419
|
+
|
|
1420
|
+
if let cached = IconBitmapCache.shared.image(forKey: cacheKey) {
|
|
1421
|
+
annotationView.image = cached
|
|
1422
|
+
return annotationView
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1425
|
+
annotationView.image = nil
|
|
1426
|
+
loadUserLocationImage(imagePath: imagePath, imageWidth: imageWidth, imageHeight: imageHeight, cacheKey: cacheKey) { [weak annotationView] image in
|
|
1427
|
+
guard let annotationView = annotationView,
|
|
1428
|
+
annotationView.accessibilityIdentifier == cacheKey else {
|
|
1429
|
+
return
|
|
1430
|
+
}
|
|
1431
|
+
annotationView.image = image
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1434
|
+
return annotationView
|
|
1435
|
+
}
|
|
1436
|
+
|
|
1437
|
+
private func userLocationImageCacheKey(imagePath: String, imageWidth: Double?, imageHeight: Double?) -> String {
|
|
1438
|
+
let widthPart = imageWidth.map { String(Int($0.rounded())) } ?? "auto"
|
|
1439
|
+
let heightPart = imageHeight.map { String(Int($0.rounded())) } ?? "auto"
|
|
1440
|
+
return "userLocation|\(imagePath)|\(widthPart)x\(heightPart)"
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
private func loadUserLocationImage(
|
|
1444
|
+
imagePath: String,
|
|
1445
|
+
imageWidth: Double?,
|
|
1446
|
+
imageHeight: Double?,
|
|
1447
|
+
cacheKey: String,
|
|
1448
|
+
completion: @escaping (UIImage?) -> Void
|
|
1449
|
+
) {
|
|
1450
|
+
let finish: (UIImage?) -> Void = { image in
|
|
1451
|
+
if let image = image {
|
|
1452
|
+
IconBitmapCache.shared.setImage(image, forKey: cacheKey)
|
|
1453
|
+
}
|
|
1454
|
+
DispatchQueue.main.async {
|
|
1455
|
+
completion(image)
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
if imagePath.hasPrefix("http://") || imagePath.hasPrefix("https://") {
|
|
1460
|
+
DispatchQueue.global(qos: .userInitiated).async { [weak self] in
|
|
1461
|
+
guard let self = self,
|
|
1462
|
+
let url = URL(string: imagePath),
|
|
1463
|
+
let data = try? Data(contentsOf: url),
|
|
1464
|
+
let image = UIImage(data: data) else {
|
|
1465
|
+
finish(nil)
|
|
1466
|
+
return
|
|
1467
|
+
}
|
|
1468
|
+
finish(self.resizeUserLocationImage(image, imageWidth: imageWidth, imageHeight: imageHeight))
|
|
1469
|
+
}
|
|
1470
|
+
return
|
|
1471
|
+
}
|
|
1472
|
+
|
|
1473
|
+
let image: UIImage?
|
|
1474
|
+
if imagePath.hasPrefix("file://") {
|
|
1475
|
+
let path = String(imagePath.dropFirst(7))
|
|
1476
|
+
image = UIImage(contentsOfFile: path)
|
|
1477
|
+
} else {
|
|
1478
|
+
image = UIImage(named: imagePath)
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
guard let image = image else {
|
|
1482
|
+
finish(nil)
|
|
1483
|
+
return
|
|
1484
|
+
}
|
|
1485
|
+
finish(resizeUserLocationImage(image, imageWidth: imageWidth, imageHeight: imageHeight))
|
|
1486
|
+
}
|
|
1487
|
+
|
|
1488
|
+
private func resizeUserLocationImage(_ image: UIImage, imageWidth: Double?, imageHeight: Double?) -> UIImage {
|
|
1489
|
+
guard let imageWidth = imageWidth,
|
|
1490
|
+
let imageHeight = imageHeight,
|
|
1491
|
+
imageWidth > 0,
|
|
1492
|
+
imageHeight > 0 else {
|
|
1493
|
+
return image
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
let targetSize = CGSize(width: imageWidth, height: imageHeight)
|
|
1497
|
+
let renderer = UIGraphicsImageRenderer(size: targetSize)
|
|
1498
|
+
return renderer.image { _ in
|
|
1499
|
+
image.draw(in: CGRect(origin: .zero, size: targetSize))
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1502
|
+
|
|
1265
1503
|
/**
|
|
1266
1504
|
* 创建标注视图
|
|
1267
|
-
*
|
|
1505
|
+
* 定位蓝点默认返回 nil 使用系统样式;传入 image 时按官方建议自定义定位 annotationView。
|
|
1268
1506
|
*/
|
|
1269
1507
|
public func mapView(_ mapView: MAMapView, viewFor annotation: MAAnnotation) -> MAAnnotationView? {
|
|
1270
1508
|
if annotation.isKind(of: MAUserLocation.self) {
|
|
1271
|
-
return
|
|
1509
|
+
return getUserLocationAnnotationView(for: mapView, annotation: annotation)
|
|
1272
1510
|
}
|
|
1273
1511
|
|
|
1274
1512
|
// 🔑 支持 MAAnimatedAnnotation(平滑移动)
|
|
@@ -43,6 +43,11 @@ public class ExpoGaodeMapViewModule: Module {
|
|
|
43
43
|
Prop("zoomGesturesEnabled") { (view: ExpoGaodeMapView, enabled: Bool) in
|
|
44
44
|
view.isZoomEnabled = enabled
|
|
45
45
|
}
|
|
46
|
+
|
|
47
|
+
// 缩放手势锚点:gesture 使用手势焦点,center 固定地图中心点
|
|
48
|
+
Prop("zoomGestureAnchor") { (view: ExpoGaodeMapView, anchor: String?) in
|
|
49
|
+
view.zoomGestureAnchor = anchor == "center" ? "center" : "gesture"
|
|
50
|
+
}
|
|
46
51
|
|
|
47
52
|
Prop("scrollGesturesEnabled") { (view: ExpoGaodeMapView, enabled: Bool) in
|
|
48
53
|
view.isScrollEnabled = enabled
|
|
@@ -172,6 +172,9 @@ class UIManager: NSObject, MAMapViewDelegate {
|
|
|
172
172
|
// 是否显示方向指示
|
|
173
173
|
if let showsHeadingIndicator = config["showsHeadingIndicator"] as? Bool {
|
|
174
174
|
representation.showsHeadingIndicator = showsHeadingIndicator
|
|
175
|
+
if showsHeadingIndicator {
|
|
176
|
+
mapView.userTrackingMode = .followWithHeading
|
|
177
|
+
}
|
|
175
178
|
}
|
|
176
179
|
|
|
177
180
|
// 精度圈填充颜色
|