expo-gaode-map 2.2.29 → 2.2.30-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.
@@ -32,6 +32,10 @@ import androidx.core.graphics.withTranslation
32
32
  @SuppressLint("ViewConstructor")
33
33
  class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(context, appContext) {
34
34
 
35
+ init {
36
+ orientation = VERTICAL
37
+ }
38
+
35
39
  /**
36
40
  * 拦截 React Native 的 ViewManager 操作
37
41
  * 重写 requestLayout 防止在移除视图时触发布局异常
@@ -44,6 +48,63 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
44
48
  }
45
49
  }
46
50
 
51
+ override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
52
+ val measuredWidth = View.MeasureSpec.getSize(widthMeasureSpec)
53
+ val measuredHeight = View.MeasureSpec.getSize(heightMeasureSpec)
54
+
55
+ setMeasuredDimension(measuredWidth, measuredHeight)
56
+
57
+ for (i in 0 until childCount) {
58
+ val child = getChildAt(i) ?: continue
59
+ if (child.visibility == View.GONE) {
60
+ continue
61
+ }
62
+
63
+ if (child === mapView) {
64
+ val childWidthSpec = View.MeasureSpec.makeMeasureSpec(measuredWidth, View.MeasureSpec.EXACTLY)
65
+ val childHeightSpec = View.MeasureSpec.makeMeasureSpec(measuredHeight, View.MeasureSpec.EXACTLY)
66
+ child.measure(childWidthSpec, childHeightSpec)
67
+ continue
68
+ }
69
+
70
+ val lp = child.layoutParams
71
+ val childWidthSpec = when {
72
+ lp?.width != null && lp.width > 0 ->
73
+ View.MeasureSpec.makeMeasureSpec(lp.width, View.MeasureSpec.EXACTLY)
74
+ else ->
75
+ View.MeasureSpec.makeMeasureSpec(measuredWidth, View.MeasureSpec.AT_MOST)
76
+ }
77
+ val childHeightSpec = when {
78
+ lp?.height != null && lp.height > 0 ->
79
+ View.MeasureSpec.makeMeasureSpec(lp.height, View.MeasureSpec.EXACTLY)
80
+ else ->
81
+ View.MeasureSpec.makeMeasureSpec(measuredHeight, View.MeasureSpec.AT_MOST)
82
+ }
83
+ child.measure(childWidthSpec, childHeightSpec)
84
+ }
85
+ }
86
+
87
+ override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
88
+ val width = right - left
89
+ val height = bottom - top
90
+
91
+ for (i in 0 until childCount) {
92
+ val child = getChildAt(i) ?: continue
93
+ if (child.visibility == View.GONE) {
94
+ continue
95
+ }
96
+
97
+ if (child === mapView) {
98
+ child.layout(0, 0, width, height)
99
+ continue
100
+ }
101
+
102
+ val childWidth = child.measuredWidth
103
+ val childHeight = child.measuredHeight
104
+ child.layout(0, 0, childWidth, childHeight)
105
+ }
106
+ }
107
+
47
108
  // Props 存储
48
109
  /** 地图类型 */
49
110
  internal var mapType: Int = 0
@@ -617,9 +678,10 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
617
678
  override fun addView(child: View?, index: Int) {
618
679
  if (child is MarkerView) {
619
680
  child.setMap(aMap)
620
- // MarkerView 也加入实际视图层级,但设置为 0x0 大小并移到屏幕外
621
- // 不使用 View.GONE,避免在新架构下出现渲染问题
622
- val params = LayoutParams(0, 0)
681
+ // MarkerView 需要保留可测量尺寸,否则 Android 无法正确处理
682
+ // Text / View 的 maxWidth 等布局约束,最终会被测成整行宽度。
683
+ // 这里保留 WRAP_CONTENT,并继续移到屏幕外,避免影响可见布局。
684
+ val params = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)
623
685
  child.layoutParams = params
624
686
  child.translationX = -10000f // 移到屏幕外
625
687
  child.translationY = -10000f
@@ -729,7 +791,4 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
729
791
  return false
730
792
  }
731
793
 
732
- override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
733
- super.onLayout(changed, left, top, right, bottom)
734
- }
735
794
  }
@@ -5,6 +5,8 @@ import android.content.Context
5
5
  import android.graphics.Bitmap
6
6
  import android.graphics.BitmapFactory
7
7
  import android.graphics.Canvas
8
+ import android.graphics.Color
9
+ import android.graphics.Rect
8
10
 
9
11
  import android.os.Handler
10
12
  import android.os.Looper
@@ -41,6 +43,8 @@ import expo.modules.gaodemap.companion.BitmapDescriptorCache
41
43
  import expo.modules.gaodemap.companion.IconBitmapCache
42
44
  import expo.modules.gaodemap.utils.GeometryUtils
43
45
  import kotlin.text.StringBuilder
46
+ import kotlin.math.max
47
+ import kotlin.math.min
44
48
 
45
49
  import java.util.concurrent.CountDownLatch
46
50
  import java.util.concurrent.TimeUnit
@@ -53,6 +57,7 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
53
57
  // 不可交互,通过父视图定位到屏幕外
54
58
  isClickable = false
55
59
  isFocusable = false
60
+ isBaselineAligned = false
56
61
  // 设置为水平方向(默认),让子视图自然布局
57
62
  orientation = HORIZONTAL
58
63
  }
@@ -118,11 +123,98 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
118
123
  }
119
124
  }
120
125
 
121
- try {
126
+ if (childCount == 0) {
122
127
  super.onMeasure(widthMeasureSpec, heightMeasureSpec)
123
- } catch (e: Exception) {
124
- throw e
128
+ return
129
+ }
130
+
131
+ val parentWidthSize = MeasureSpec.getSize(widthMeasureSpec)
132
+ val parentHeightSize = MeasureSpec.getSize(heightMeasureSpec)
133
+ val fallbackWidthSize = resolveExplicitMeasureSize(parentWidthSize, true)
134
+ val fallbackHeightSize = resolveExplicitMeasureSize(parentHeightSize, false)
135
+
136
+ val contentWidthSpec = when {
137
+ customViewWidth > 0 -> MeasureSpec.makeMeasureSpec(customViewWidth, MeasureSpec.EXACTLY)
138
+ fallbackWidthSize > 0 -> MeasureSpec.makeMeasureSpec(fallbackWidthSize, MeasureSpec.AT_MOST)
139
+ else -> MeasureSpec.makeMeasureSpec(1, MeasureSpec.EXACTLY)
140
+ }
141
+ val contentHeightSpec = when {
142
+ customViewHeight > 0 -> MeasureSpec.makeMeasureSpec(customViewHeight, MeasureSpec.EXACTLY)
143
+ fallbackHeightSize > 0 -> MeasureSpec.makeMeasureSpec(fallbackHeightSize, MeasureSpec.AT_MOST)
144
+ else -> MeasureSpec.makeMeasureSpec(1, MeasureSpec.EXACTLY)
145
+ }
146
+
147
+ var measuredContentWidth = 0
148
+ var measuredContentHeight = 0
149
+
150
+ for (i in 0 until childCount) {
151
+ val child = getChildAt(i)
152
+ val lp = child.layoutParams as? LayoutParams
153
+ ?: LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)
154
+
155
+ val childWidthSpec = getChildMeasureSpec(
156
+ contentWidthSpec,
157
+ paddingLeft + paddingRight,
158
+ lp.width
159
+ )
160
+ val childHeightSpec = getChildMeasureSpec(
161
+ contentHeightSpec,
162
+ paddingTop + paddingBottom,
163
+ lp.height
164
+ )
165
+
166
+ child.measure(childWidthSpec, childHeightSpec)
167
+ val childBounds = computeContentBounds(child)
168
+ measuredContentWidth = max(measuredContentWidth, childBounds?.width() ?: child.measuredWidth)
169
+ measuredContentHeight = max(measuredContentHeight, childBounds?.height() ?: child.measuredHeight)
170
+ }
171
+
172
+ val desiredWidth = if (customViewWidth > 0) {
173
+ customViewWidth
174
+ } else {
175
+ measuredContentWidth + paddingLeft + paddingRight
176
+ }
177
+ val desiredHeight = if (customViewHeight > 0) {
178
+ customViewHeight
179
+ } else {
180
+ measuredContentHeight + paddingTop + paddingBottom
181
+ }
182
+
183
+ val finalWidth = if (parentWidthSize > 0) min(desiredWidth, parentWidthSize) else desiredWidth
184
+ val finalHeight = if (parentHeightSize > 0) min(desiredHeight, parentHeightSize) else desiredHeight
185
+
186
+ setMeasuredDimension(
187
+ max(finalWidth, suggestedMinimumWidth),
188
+ max(finalHeight, suggestedMinimumHeight)
189
+ )
190
+ }
191
+
192
+ private fun resolveExplicitMeasureSize(parentSize: Int, isWidth: Boolean): Int {
193
+ if (parentSize > 0) {
194
+ return parentSize
195
+ }
196
+
197
+ val parentView = parent as? View
198
+ val parentMeasuredSize = if (isWidth) {
199
+ parentView?.measuredWidth ?: 0
200
+ } else {
201
+ parentView?.measuredHeight ?: 0
202
+ }
203
+ if (parentMeasuredSize > 0) {
204
+ return parentMeasuredSize
205
+ }
206
+
207
+ val parentLayoutSize = if (isWidth) {
208
+ parentView?.width ?: 0
209
+ } else {
210
+ parentView?.height ?: 0
211
+ }
212
+ if (parentLayoutSize > 0) {
213
+ return parentLayoutSize
125
214
  }
215
+
216
+ val displayMetrics = context.resources.displayMetrics
217
+ return if (isWidth) displayMetrics.widthPixels else displayMetrics.heightPixels
126
218
  }
127
219
 
128
220
  private val onMarkerPress by EventDispatcher()
@@ -141,6 +233,8 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
141
233
  private var customViewHeight: Int = 0 // 用于自定义视图(children)的高度
142
234
  private val mainHandler = Handler(Looper.getMainLooper())
143
235
  private var isRemoving = false // 标记是否正在被移除
236
+ private var pendingMarkerIconUpdate: Runnable? = null
237
+ private var lastAppliedCustomMarkerKey: String? = null
144
238
 
145
239
  // 缓存属性,在 marker 创建前保存
146
240
  private var pendingTitle: String? = null
@@ -789,8 +883,10 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
789
883
  val keyPart = cacheKey ?: computeViewFingerprint(this)
790
884
 
791
885
  val measuredChild = if (isNotEmpty()) getChildAt(0) else null
792
- val measuredWidth = measuredChild?.measuredWidth ?: 0
793
- val measuredHeight = measuredChild?.measuredHeight ?: 0
886
+ val contentView = resolveRenderableContentView(measuredChild)
887
+ val contentBounds = computeContentBounds(measuredChild)
888
+ val measuredWidth = contentBounds?.width() ?: contentView?.measuredWidth ?: measuredChild?.measuredWidth ?: 0
889
+ val measuredHeight = contentBounds?.height() ?: contentView?.measuredHeight ?: measuredChild?.measuredHeight ?: 0
794
890
 
795
891
  val finalWidth = if (measuredWidth > 0) measuredWidth else (if (customViewWidth > 0) customViewWidth else 0)
796
892
  val finalHeight = if (measuredHeight > 0) measuredHeight else (if (customViewHeight > 0) customViewHeight else 0)
@@ -873,13 +969,85 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
873
969
  childView.isDrawingCacheEnabled = false
874
970
  childView.destroyDrawingCache()
875
971
 
876
- return bitmap
972
+ val shouldTrimTransparentPadding = customViewWidth <= 0 && customViewHeight <= 0
973
+ return if (shouldTrimTransparentPadding) trimTransparentPadding(bitmap) else bitmap
877
974
  } catch (_: Exception) {
878
975
  // 遇到异常时返回 null,让上层使用默认图标
879
976
  return null
880
977
  }
881
978
  }
882
979
 
980
+ private fun trimTransparentPadding(bitmap: Bitmap): Bitmap {
981
+ if (bitmap.width <= 1 || bitmap.height <= 1) {
982
+ return bitmap
983
+ }
984
+
985
+ if (hasOpaquePixelsOnAllBitmapEdges(bitmap)) {
986
+ return bitmap
987
+ }
988
+
989
+ var minX = bitmap.width
990
+ var minY = bitmap.height
991
+ var maxX = -1
992
+ var maxY = -1
993
+
994
+ for (y in 0 until bitmap.height) {
995
+ for (x in 0 until bitmap.width) {
996
+ if (Color.alpha(bitmap.getPixel(x, y)) != 0) {
997
+ if (x < minX) minX = x
998
+ if (y < minY) minY = y
999
+ if (x > maxX) maxX = x
1000
+ if (y > maxY) maxY = y
1001
+ }
1002
+ }
1003
+ }
1004
+
1005
+ if (maxX < minX || maxY < minY) {
1006
+ return bitmap
1007
+ }
1008
+
1009
+ val trimmedWidth = maxX - minX + 1
1010
+ val trimmedHeight = maxY - minY + 1
1011
+ if (trimmedWidth == bitmap.width && trimmedHeight == bitmap.height) {
1012
+ return bitmap
1013
+ }
1014
+
1015
+ return Bitmap.createBitmap(bitmap, minX, minY, trimmedWidth, trimmedHeight)
1016
+ }
1017
+
1018
+ private fun hasOpaquePixelsOnAllBitmapEdges(bitmap: Bitmap): Boolean {
1019
+ var topEdgeHasPixel = false
1020
+ var bottomEdgeHasPixel = false
1021
+ var leftEdgeHasPixel = false
1022
+ var rightEdgeHasPixel = false
1023
+
1024
+ for (x in 0 until bitmap.width) {
1025
+ if (!topEdgeHasPixel && Color.alpha(bitmap.getPixel(x, 0)) != 0) {
1026
+ topEdgeHasPixel = true
1027
+ }
1028
+ if (!bottomEdgeHasPixel && Color.alpha(bitmap.getPixel(x, bitmap.height - 1)) != 0) {
1029
+ bottomEdgeHasPixel = true
1030
+ }
1031
+ if (topEdgeHasPixel && bottomEdgeHasPixel) {
1032
+ break
1033
+ }
1034
+ }
1035
+
1036
+ for (y in 0 until bitmap.height) {
1037
+ if (!leftEdgeHasPixel && Color.alpha(bitmap.getPixel(0, y)) != 0) {
1038
+ leftEdgeHasPixel = true
1039
+ }
1040
+ if (!rightEdgeHasPixel && Color.alpha(bitmap.getPixel(bitmap.width - 1, y)) != 0) {
1041
+ rightEdgeHasPixel = true
1042
+ }
1043
+ if (leftEdgeHasPixel && rightEdgeHasPixel) {
1044
+ break
1045
+ }
1046
+ }
1047
+
1048
+ return topEdgeHasPixel && bottomEdgeHasPixel && leftEdgeHasPixel && rightEdgeHasPixel
1049
+ }
1050
+
883
1051
  /**
884
1052
  * 更新 marker 图标
885
1053
  */
@@ -887,6 +1055,7 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
887
1055
  if (isEmpty()) {
888
1056
  // 如果确实为空(没有子视图),恢复默认样式
889
1057
  marker?.setIcon(BitmapDescriptorFactory.defaultMarker())
1058
+ lastAppliedCustomMarkerKey = null
890
1059
  // 恢复默认锚点(底部中心),除非用户指定了锚点
891
1060
  val anchorX = pendingAnchor?.first ?: 0.5f
892
1061
  val anchorY = pendingAnchor?.second ?: 1.0f
@@ -898,18 +1067,27 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
898
1067
  // 构建缓存 key(优先 JS 端 cacheKey)
899
1068
  val keyPart = cacheKey ?: computeViewFingerprint(this)
900
1069
  val child = getChildAt(0)
901
- val measuredWidth = child?.measuredWidth ?: customViewWidth
902
- val measuredHeight = child?.measuredHeight ?: customViewHeight
1070
+ val contentView = resolveRenderableContentView(child)
1071
+ val contentBounds = computeContentBounds(child)
1072
+ val measuredWidth = contentBounds?.width() ?: contentView?.measuredWidth ?: child?.measuredWidth ?: customViewWidth
1073
+ val measuredHeight = contentBounds?.height() ?: contentView?.measuredHeight ?: child?.measuredHeight ?: customViewHeight
903
1074
  val fullCacheKey = "$keyPart|${measuredWidth}x${measuredHeight}"
904
1075
 
905
1076
  // 确定锚点:优先使用用户指定的 pendingAnchor,否则对于自定义 View 使用中心点 (0.5, 0.5)
906
1077
  val anchorX = pendingAnchor?.first ?: 0.5f
907
1078
  val anchorY = pendingAnchor?.second ?: 0.5f
908
1079
 
1080
+ if (fullCacheKey == lastAppliedCustomMarkerKey) {
1081
+ marker?.setAnchor(anchorX, anchorY)
1082
+ marker?.let { showMarker(it) }
1083
+ return
1084
+ }
1085
+
909
1086
  // 1) 尝试 BitmapDescriptor 缓存
910
1087
  BitmapDescriptorCache.get(fullCacheKey)?.let { it ->
911
1088
  marker?.setIcon(it)
912
1089
  marker?.setAnchor(anchorX, anchorY)
1090
+ lastAppliedCustomMarkerKey = fullCacheKey
913
1091
  marker?.let { showMarker(it) }
914
1092
  return
915
1093
  }
@@ -933,9 +1111,31 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
933
1111
  // 设置到 Marker
934
1112
  marker?.setIcon(descriptor)
935
1113
  marker?.setAnchor(anchorX, anchorY)
1114
+ lastAppliedCustomMarkerKey = fullCacheKey
936
1115
  marker?.let { showMarker(it) }
937
1116
  }
938
1117
 
1118
+ private fun scheduleMarkerIconUpdate(delayMs: Long = 16L) {
1119
+ if (isRemoving || marker == null || isEmpty()) {
1120
+ return
1121
+ }
1122
+
1123
+ pendingMarkerIconUpdate?.let { mainHandler.removeCallbacks(it) }
1124
+ val task = Runnable {
1125
+ pendingMarkerIconUpdate = null
1126
+ if (!isRemoving && marker != null && isNotEmpty()) {
1127
+ updateMarkerIcon()
1128
+ }
1129
+ }
1130
+ pendingMarkerIconUpdate = task
1131
+
1132
+ if (delayMs <= 0L) {
1133
+ mainHandler.post(task)
1134
+ } else {
1135
+ mainHandler.postDelayed(task, delayMs)
1136
+ }
1137
+ }
1138
+
939
1139
 
940
1140
 
941
1141
  override fun removeView(child: View?) {
@@ -957,11 +1157,7 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
957
1157
  super.removeViewAt(index)
958
1158
  // 只在还有子视图时更新图标
959
1159
  if (!isRemoving && childCount > 1 && marker != null) {
960
- mainHandler.postDelayed({
961
- if (!isRemoving && marker != null && isNotEmpty()) {
962
- updateMarkerIcon()
963
- }
964
- }, 50)
1160
+ scheduleMarkerIconUpdate(50)
965
1161
  }
966
1162
  // 如果最后一个子视图被移除,什么都不做
967
1163
  // 让 onDetachedFromWindow 处理完整的清理
@@ -970,35 +1166,82 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
970
1166
  // 忽略异常
971
1167
  }
972
1168
  }
973
- /**
974
- * 递归修复子视图的 LayoutParams,确保所有子视图都使用正确的 LayoutParams 类型
975
- */
976
- private fun fixChildLayoutParams(view: View) {
977
- if (view is ViewGroup) {
978
- for (i in 0 until view.childCount) {
979
- val child = view.getChildAt(i)
980
- val currentParams = child.layoutParams
981
- if (currentParams != null && currentParams !is LayoutParams) {
982
- child.layoutParams = LayoutParams(
983
- currentParams.width,
984
- currentParams.height
985
- )
986
- }
987
- fixChildLayoutParams(child)
1169
+ private fun resolveRenderableContentView(view: View?): View? {
1170
+ var current = view ?: return null
1171
+
1172
+ while (current is ViewGroup && current.childCount == 1) {
1173
+ val next = current.getChildAt(0) ?: break
1174
+ current = next
1175
+ }
1176
+
1177
+ return current
1178
+ }
1179
+
1180
+ private fun computeContentBounds(view: View?): Rect? {
1181
+ view ?: return null
1182
+ if (view.visibility != View.VISIBLE) return null
1183
+
1184
+ var resolvedBounds: Rect? = null
1185
+
1186
+ if (view is ViewGroup && view.childCount > 0) {
1187
+ for (i in 0 until view.childCount) {
1188
+ val child = view.getChildAt(i) ?: continue
1189
+ val childBounds = computeContentBounds(child) ?: continue
1190
+ val shiftedBounds = Rect(childBounds)
1191
+ shiftedBounds.offset(child.left, child.top)
1192
+ resolvedBounds = if (resolvedBounds == null) {
1193
+ shiftedBounds
1194
+ } else {
1195
+ Rect(resolvedBounds).apply { union(shiftedBounds) }
988
1196
  }
1197
+ }
1198
+ }
1199
+
1200
+ val hasOwnVisualBounds =
1201
+ view.background != null ||
1202
+ view.paddingLeft != 0 ||
1203
+ view.paddingTop != 0 ||
1204
+ view.paddingRight != 0 ||
1205
+ view.paddingBottom != 0 ||
1206
+ view !is ViewGroup
1207
+
1208
+ val ownWidth = view.measuredWidth.takeIf { it > 0 } ?: view.width
1209
+ val ownHeight = view.measuredHeight.takeIf { it > 0 } ?: view.height
1210
+
1211
+ if (hasOwnVisualBounds && ownWidth > 0 && ownHeight > 0) {
1212
+ val ownBounds = Rect(0, 0, ownWidth, ownHeight)
1213
+ resolvedBounds = if (resolvedBounds == null) {
1214
+ ownBounds
1215
+ } else {
1216
+ Rect(resolvedBounds).apply { union(ownBounds) }
1217
+ }
989
1218
  }
1219
+
1220
+ return resolvedBounds
990
1221
  }
991
1222
 
992
1223
 
993
1224
  override fun addView(child: View?, index: Int, params: android.view.ViewGroup.LayoutParams?) {
994
1225
  // 🔑 关键修复:记录添加前的子视图数量
995
1226
  val childCountBefore = childCount
1227
+
1228
+ val sourceWidth = when {
1229
+ customViewWidth > 0 -> customViewWidth
1230
+ params?.width != null && params.width > 0 -> params.width
1231
+ else -> LayoutParams.WRAP_CONTENT
1232
+ }
1233
+
1234
+ val sourceHeight = when {
1235
+ customViewHeight > 0 -> customViewHeight
1236
+ params?.height != null && params.height > 0 -> params.height
1237
+ else -> LayoutParams.WRAP_CONTENT
1238
+ }
996
1239
 
997
1240
  val finalParams = LayoutParams(
998
- if (customViewWidth > 0) customViewWidth else LayoutParams.WRAP_CONTENT,
999
- if (customViewHeight > 0) customViewHeight else LayoutParams.WRAP_CONTENT
1241
+ sourceWidth,
1242
+ sourceHeight
1000
1243
  )
1001
-
1244
+
1002
1245
  super.addView(child, index, finalParams)
1003
1246
 
1004
1247
  child?.let {
@@ -1009,17 +1252,12 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
1009
1252
  childParams?.height ?: LayoutParams.WRAP_CONTENT
1010
1253
  )
1011
1254
  }
1012
- fixChildLayoutParams(it)
1013
1255
  }
1014
1256
 
1015
1257
  // 🔑 修复:需要延迟更新图标,等待 children 完成布局
1016
1258
  // 原因:立即更新会在 children 还未完成测量/布局时就渲染,导致内容为空
1017
1259
  if (!isRemoving && marker != null && childCount > childCountBefore) {
1018
- mainHandler.post {
1019
- if (!isRemoving && marker != null && isNotEmpty()) {
1020
- updateMarkerIcon()
1021
- }
1022
- }
1260
+ scheduleMarkerIconUpdate()
1023
1261
  }
1024
1262
  }
1025
1263
 
@@ -1028,11 +1266,7 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
1028
1266
  // 🔑 修复:布局完成后延迟更新图标
1029
1267
  // 即使 changed 为 false,只要有内容,也应该检查是否需要更新(例如子 View 尺寸变化但 MarkerView 没变)
1030
1268
  if (!isRemoving && isNotEmpty() && marker != null) {
1031
- mainHandler.post {
1032
- if (!isRemoving && marker != null && isNotEmpty()) {
1033
- updateMarkerIcon()
1034
- }
1035
- }
1269
+ scheduleMarkerIconUpdate()
1036
1270
  }
1037
1271
  }
1038
1272
 
@@ -1239,6 +1473,7 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
1239
1473
  private fun stopSmoothMove() {
1240
1474
  smoothMoveMarker?.stopMove()
1241
1475
  smoothMoveMarker?.setVisible(false)
1476
+ lastAppliedCustomMarkerKey = null
1242
1477
  marker?.let { showMarker(it) }
1243
1478
  }
1244
1479
 
@@ -1264,6 +1499,7 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
1264
1499
  // 🔑 关键修复:使用 post 延迟检查
1265
1500
  // 清理所有延迟任务
1266
1501
  mainHandler.removeCallbacksAndMessages(null)
1502
+ pendingMarkerIconUpdate = null
1267
1503
 
1268
1504
  // 延迟检查 parent 状态
1269
1505
  mainHandler.post {
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoGaodeMapModule.d.ts","sourceRoot":"","sources":["../src/ExpoGaodeMapModule.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ExpoGaodeMapModule.d.ts","sourceRoot":"","sources":["../src/ExpoGaodeMapModule.ts"],"names":[],"mappings":"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"}
@@ -741,16 +741,35 @@ const helperMethods = {
741
741
  try {
742
742
  const normalizedPoint = normalizeLatLng(point);
743
743
  let normalizedPolygons;
744
+ let ringToPolygonIndex = null;
744
745
  // 处理三维数组 (LatLngPoint[][][]) 和二维数组 (LatLngPoint[][])
745
746
  if (Array.isArray(polygons[0]) && Array.isArray(polygons[0][0])) {
746
747
  // LatLngPoint[][][] -> 扁平化为 LatLngPoint[][] 用于 C++ 遍历
747
- normalizedPolygons = polygons.reduce((acc, val) => acc.concat(val), []);
748
+ // 同时记录每个 Ring 对应的原始多边形索引
749
+ normalizedPolygons = [];
750
+ ringToPolygonIndex = [];
751
+ polygons.forEach((polygonRings, index) => {
752
+ polygonRings.forEach((ring) => {
753
+ normalizedPolygons.push(ring);
754
+ ringToPolygonIndex.push(index);
755
+ });
756
+ });
748
757
  }
749
758
  else {
750
759
  normalizedPolygons = polygons;
751
760
  }
752
- const processedPolygons = normalizedPolygons.map(p => normalizeLatLngList(p));
753
- return nativeModule.findPointInPolygons(normalizedPoint, processedPolygons);
761
+ const processedPolygons = normalizedPolygons.map((p) => normalizeLatLngList(p));
762
+ const resultIndex = nativeModule.findPointInPolygons(normalizedPoint, processedPolygons);
763
+ // 如果未命中,返回 -1
764
+ if (resultIndex === -1) {
765
+ return -1;
766
+ }
767
+ // 如果存在映射关系(带孔多边形),将 Ring 索引映射回 Polygon 索引
768
+ if (ringToPolygonIndex) {
769
+ return ringToPolygonIndex[resultIndex];
770
+ }
771
+ // 简单多边形直接返回索引
772
+ return resultIndex;
754
773
  }
755
774
  catch (error) {
756
775
  ErrorLogger.warn('findPointInPolygons 失败', { point, error });