expo-gaode-map 0.1.5 → 0.1.6

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.
@@ -368,6 +368,10 @@ class ExpoGaodeMapModule : Module() {
368
368
  Prop<Int>("strokeColor") { view: PolylineView, color ->
369
369
  view.setStrokeColor(color)
370
370
  }
371
+
372
+ Prop<String?>("texture") { view: PolylineView, texture ->
373
+ view.setTexture(texture)
374
+ }
371
375
  }
372
376
 
373
377
  // Polygon - 多边形
@@ -1,9 +1,12 @@
1
1
  package expo.modules.gaodemap.managers
2
2
 
3
3
  import android.util.Log
4
+ import android.graphics.BitmapFactory
4
5
  import com.amap.api.maps.AMap
5
6
  import com.amap.api.maps.model.LatLng
7
+ import com.amap.api.maps.model.BitmapDescriptorFactory
6
8
  import expo.modules.gaodemap.utils.ColorParser
9
+ import java.net.URL
7
10
 
8
11
  /**
9
12
  * 覆盖物管理器
@@ -151,9 +154,14 @@ class OverlayManager(private val aMap: AMap) {
151
154
  @Suppress("UNCHECKED_CAST")
152
155
  val points = props["points"] as? List<Map<String, Double>>
153
156
  val width = (props["width"] as? Number)?.toFloat() ?: 10f
154
- val color = ColorParser.parseColor(props["color"])
157
+ val texture = props["texture"] as? String
158
+ val color = if (!texture.isNullOrEmpty()) {
159
+ android.graphics.Color.TRANSPARENT
160
+ } else {
161
+ ColorParser.parseColor(props["color"])
162
+ }
155
163
 
156
- if (points != null && points.isNotEmpty()) {
164
+ if (points != null && points.size >= 2) {
157
165
  val latLngs = points.map { point ->
158
166
  val lat = point["latitude"] ?: 0.0
159
167
  val lng = point["longitude"] ?: 0.0
@@ -166,6 +174,30 @@ class OverlayManager(private val aMap: AMap) {
166
174
  .color(color)
167
175
 
168
176
  val polyline = aMap.addPolyline(options)
177
+
178
+ // 处理纹理
179
+ if (!texture.isNullOrEmpty()) {
180
+ Thread {
181
+ try {
182
+ val bitmap = if (texture.startsWith("http://") || texture.startsWith("https://")) {
183
+ BitmapFactory.decodeStream(URL(texture).openStream())
184
+ } else if (texture.startsWith("file://")) {
185
+ BitmapFactory.decodeFile(texture.substring(7))
186
+ } else {
187
+ null
188
+ }
189
+
190
+ bitmap?.let {
191
+ val descriptor = BitmapDescriptorFactory.fromBitmap(it)
192
+ polyline.setCustomTexture(descriptor)
193
+ Log.d(TAG, "✅ 纹理设置成功")
194
+ }
195
+ } catch (e: Exception) {
196
+ Log.e(TAG, "纹理加载失败: ${e.message}")
197
+ }
198
+ }.start()
199
+ }
200
+
169
201
  polylines[id] = polyline
170
202
  Log.d(TAG, "✅ 折线创建成功")
171
203
  }
@@ -3,12 +3,14 @@ package expo.modules.gaodemap.overlays
3
3
  import android.content.Context
4
4
  import android.graphics.Color
5
5
  import com.amap.api.maps.AMap
6
+ import com.amap.api.maps.model.BitmapDescriptorFactory
6
7
  import com.amap.api.maps.model.LatLng
7
8
  import com.amap.api.maps.model.Polyline
8
9
  import com.amap.api.maps.model.PolylineOptions
9
10
  import expo.modules.kotlin.AppContext
10
11
  import expo.modules.kotlin.viewevent.EventDispatcher
11
12
  import expo.modules.kotlin.views.ExpoView
13
+ import java.net.URL
12
14
 
13
15
  class PolylineView(context: Context, appContext: AppContext) : ExpoView(context, appContext) {
14
16
 
@@ -17,6 +19,7 @@ class PolylineView(context: Context, appContext: AppContext) : ExpoView(context,
17
19
  private var polyline: Polyline? = null
18
20
  private var aMap: AMap? = null
19
21
  private var points: List<LatLng> = emptyList()
22
+ private var textureUrl: String? = null
20
23
 
21
24
  /**
22
25
  * 设置地图实例
@@ -92,7 +95,6 @@ class PolylineView(context: Context, appContext: AppContext) : ExpoView(context,
92
95
  * 设置透明度
93
96
  */
94
97
  fun setOpacity(opacity: Float) {
95
- // 通过修改颜色的 alpha 通道实现透明度
96
98
  polyline?.let { line ->
97
99
  val currentColor = line.color
98
100
  val alpha = (opacity * 255).toInt()
@@ -100,20 +102,69 @@ class PolylineView(context: Context, appContext: AppContext) : ExpoView(context,
100
102
  }
101
103
  }
102
104
 
105
+ /**
106
+ * 设置纹理图片
107
+ */
108
+ fun setTexture(url: String?) {
109
+ textureUrl = url
110
+ createOrUpdatePolyline()
111
+ }
112
+
103
113
  /**
104
114
  * 创建或更新折线
105
115
  */
106
116
  private fun createOrUpdatePolyline() {
107
117
  aMap?.let { map ->
108
- if (polyline == null && points.isNotEmpty()) {
118
+ // 移除旧折线
119
+ polyline?.remove()
120
+ polyline = null
121
+
122
+ if (points.isNotEmpty()) {
109
123
  val options = PolylineOptions()
110
124
  .addAll(points)
111
125
  .width(10f)
112
126
  .color(Color.BLUE)
113
127
 
128
+ // 设置纹理
129
+ textureUrl?.let { url ->
130
+ try {
131
+ when {
132
+ url.startsWith("http://") || url.startsWith("https://") -> {
133
+ // 网络图片异步加载
134
+ Thread {
135
+ try {
136
+ val connection = URL(url).openConnection()
137
+ val inputStream = connection.getInputStream()
138
+ val bitmap = android.graphics.BitmapFactory.decodeStream(inputStream)
139
+ inputStream.close()
140
+ post {
141
+ polyline?.setCustomTexture(BitmapDescriptorFactory.fromBitmap(bitmap))
142
+ }
143
+ } catch (e: Exception) {
144
+ e.printStackTrace()
145
+ }
146
+ }.start()
147
+ }
148
+ url.startsWith("file://") -> {
149
+ val path = url.substring(7)
150
+ val bitmap = android.graphics.BitmapFactory.decodeFile(path)
151
+ bitmap?.let { options.setCustomTexture(BitmapDescriptorFactory.fromBitmap(it)) }
152
+ }
153
+ else -> {
154
+ val resId = context.resources.getIdentifier(url, "drawable", context.packageName)
155
+ if (resId != 0) {
156
+ val bitmap = android.graphics.BitmapFactory.decodeResource(context.resources, resId)
157
+ options.setCustomTexture(BitmapDescriptorFactory.fromBitmap(bitmap))
158
+ }
159
+ }
160
+ }
161
+ } catch (e: Exception) {
162
+ e.printStackTrace()
163
+ }
164
+ }
165
+
114
166
  polyline = map.addPolyline(options)
115
167
 
116
- // 设置点击监听
117
168
  map.setOnPolylineClickListener { clickedPolyline ->
118
169
  if (clickedPolyline == polyline) {
119
170
  onPress(mapOf("id" to clickedPolyline.id))
@@ -1 +1 @@
1
- {"version":3,"file":"Polyline.d.ts","sourceRoot":"","sources":["../../../src/components/overlays/Polyline.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,KAAK,EAAE,aAAa,QA4BpD"}
1
+ {"version":3,"file":"Polyline.d.ts","sourceRoot":"","sources":["../../../src/components/overlays/Polyline.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,KAAK,EAAE,aAAa,QAyBpD"}
@@ -2,7 +2,7 @@
2
2
  * @Author : 尚博信_王强 wangqiang03@sunboxsoft.com
3
3
  * @Date : 2025-11-13 15:01:30
4
4
  * @LastEditors : 尚博信_王强 wangqiang03@sunboxsoft.com
5
- * @LastEditTime : 2025-11-14 15:48:14
5
+ * @LastEditTime : 2025-11-15 01:08:27
6
6
  * @FilePath : /expo-gaode-map/src/components/overlays/Polyline.tsx
7
7
  * @Description : 地图折线组件 - 使用命令式 API
8
8
  *
@@ -29,25 +29,23 @@ import { MapContext } from '../../ExpoGaodeMapView';
29
29
  */
30
30
  export default function Polyline(props) {
31
31
  const mapRef = React.useContext(MapContext);
32
- const polylineIdRef = React.useRef(`polyline_${Date.now()}_${Math.random()}`);
33
- const isInitialMount = React.useRef(true);
32
+ const polylineIdRef = React.useRef(null);
34
33
  // 添加折线
35
34
  React.useEffect(() => {
36
- const polylineId = polylineIdRef.current;
37
- mapRef?.current?.addPolyline?.(polylineId, props);
35
+ const polylineId = `polyline_${Date.now()}_${Math.random()}`;
36
+ polylineIdRef.current = polylineId;
37
+ // 只传递必要的属性
38
+ const polylineProps = {
39
+ points: props.points,
40
+ width: props.width,
41
+ color: props.color,
42
+ ...(props.texture && { texture: props.texture }),
43
+ };
44
+ mapRef?.current?.addPolyline?.(polylineId, polylineProps);
38
45
  return () => {
39
46
  mapRef?.current?.removePolyline?.(polylineId);
40
47
  };
41
48
  }, []);
42
- // 监听 Props 变化,更新折线(跳过初始渲染)
43
- React.useEffect(() => {
44
- if (isInitialMount.current) {
45
- isInitialMount.current = false;
46
- return;
47
- }
48
- const polylineId = polylineIdRef.current;
49
- mapRef?.current?.updatePolyline?.(polylineId, props);
50
- }, [props.points, props.width, props.color]);
51
49
  return null;
52
50
  }
53
51
  //# sourceMappingURL=Polyline.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Polyline.js","sourceRoot":"","sources":["../../../src/components/overlays/Polyline.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAGpD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,KAAoB;IACnD,MAAM,MAAM,GAAG,KAAK,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;IAC5C,MAAM,aAAa,GAAG,KAAK,CAAC,MAAM,CAAS,YAAY,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACtF,MAAM,cAAc,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAE1C,OAAO;IACP,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,MAAM,UAAU,GAAG,aAAa,CAAC,OAAO,CAAC;QAEzC,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QAElD,OAAO,GAAG,EAAE;YACV,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,UAAU,CAAC,CAAC;QAChD,CAAC,CAAC;IACJ,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,2BAA2B;IAC3B,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,IAAI,cAAc,CAAC,OAAO,EAAE,CAAC;YAC3B,cAAc,CAAC,OAAO,GAAG,KAAK,CAAC;YAC/B,OAAO;QACT,CAAC;QAED,MAAM,UAAU,GAAG,aAAa,CAAC,OAAO,CAAC;QACzC,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IACvD,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;IAE7C,OAAO,IAAI,CAAC;AACd,CAAC","sourcesContent":["/*\n * @Author : 尚博信_王强 wangqiang03@sunboxsoft.com\n * @Date : 2025-11-13 15:01:30\n * @LastEditors : 尚博信_王强 wangqiang03@sunboxsoft.com\n * @LastEditTime : 2025-11-14 15:48:14\n * @FilePath : /expo-gaode-map/src/components/overlays/Polyline.tsx\n * @Description : 地图折线组件 - 使用命令式 API\n * \n * Copyright (c) 2025 by 尚博信_王强, All Rights Reserved. \n */\n\nimport * as React from 'react';\nimport { MapContext } from '../../ExpoGaodeMapView';\nimport type { PolylineProps } from '../../types';\n\n/**\n * 地图折线组件\n * \n * @example\n * ```tsx\n * <MapView>\n * <Polyline\n * points={[\n * { latitude: 39.9, longitude: 116.4 },\n * { latitude: 39.91, longitude: 116.41 },\n * ]}\n * color=\"#FF0000\"\n * width={5}\n * />\n * </MapView>\n * ```\n */\nexport default function Polyline(props: PolylineProps) {\n const mapRef = React.useContext(MapContext);\n const polylineIdRef = React.useRef<string>(`polyline_${Date.now()}_${Math.random()}`);\n const isInitialMount = React.useRef(true);\n\n // 添加折线\n React.useEffect(() => {\n const polylineId = polylineIdRef.current;\n \n mapRef?.current?.addPolyline?.(polylineId, props);\n\n return () => {\n mapRef?.current?.removePolyline?.(polylineId);\n };\n }, []);\n\n // 监听 Props 变化,更新折线(跳过初始渲染)\n React.useEffect(() => {\n if (isInitialMount.current) {\n isInitialMount.current = false;\n return;\n }\n \n const polylineId = polylineIdRef.current;\n mapRef?.current?.updatePolyline?.(polylineId, props);\n }, [props.points, props.width, props.color]);\n\n return null;\n}\n"]}
1
+ {"version":3,"file":"Polyline.js","sourceRoot":"","sources":["../../../src/components/overlays/Polyline.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAGpD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,KAAoB;IACnD,MAAM,MAAM,GAAG,KAAK,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;IAC5C,MAAM,aAAa,GAAG,KAAK,CAAC,MAAM,CAAgB,IAAI,CAAC,CAAC;IAExD,OAAO;IACP,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,MAAM,UAAU,GAAG,YAAY,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;QAC7D,aAAa,CAAC,OAAO,GAAG,UAAU,CAAC;QAEnC,WAAW;QACX,MAAM,aAAa,GAAG;YACpB,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,GAAG,CAAC,KAAK,CAAC,OAAO,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC;SACjD,CAAC;QAEF,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;QAE1D,OAAO,GAAG,EAAE;YACV,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,UAAU,CAAC,CAAC;QAChD,CAAC,CAAC;IACJ,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,IAAI,CAAC;AACd,CAAC","sourcesContent":["/*\n * @Author : 尚博信_王强 wangqiang03@sunboxsoft.com\n * @Date : 2025-11-13 15:01:30\n * @LastEditors : 尚博信_王强 wangqiang03@sunboxsoft.com\n * @LastEditTime : 2025-11-15 01:08:27\n * @FilePath : /expo-gaode-map/src/components/overlays/Polyline.tsx\n * @Description : 地图折线组件 - 使用命令式 API\n * \n * Copyright (c) 2025 by 尚博信_王强, All Rights Reserved. \n */\n\nimport * as React from 'react';\nimport { MapContext } from '../../ExpoGaodeMapView';\nimport type { PolylineProps } from '../../types';\n\n/**\n * 地图折线组件\n * \n * @example\n * ```tsx\n * <MapView>\n * <Polyline\n * points={[\n * { latitude: 39.9, longitude: 116.4 },\n * { latitude: 39.91, longitude: 116.41 },\n * ]}\n * color=\"#FF0000\"\n * width={5}\n * />\n * </MapView>\n * ```\n */\nexport default function Polyline(props: PolylineProps) {\n const mapRef = React.useContext(MapContext);\n const polylineIdRef = React.useRef<string | null>(null);\n\n // 添加折线\n React.useEffect(() => {\n const polylineId = `polyline_${Date.now()}_${Math.random()}`;\n polylineIdRef.current = polylineId;\n \n // 只传递必要的属性\n const polylineProps = {\n points: props.points,\n width: props.width,\n color: props.color,\n ...(props.texture && { texture: props.texture }),\n };\n \n mapRef?.current?.addPolyline?.(polylineId, polylineProps);\n\n return () => {\n mapRef?.current?.removePolyline?.(polylineId);\n };\n }, []);\n\n return null;\n}\n"]}
@@ -111,6 +111,11 @@ export interface PolylineProps {
111
111
  * 是否绘制虚线
112
112
  */
113
113
  dotted?: boolean;
114
+ /**
115
+ * 纹理图片
116
+ * 支持网络图片(http/https)、本地文件(file://)或资源名称
117
+ */
118
+ texture?: string;
114
119
  /**
115
120
  * 点击事件
116
121
  */
@@ -1 +1 @@
1
- {"version":3,"file":"overlays.types.d.ts","sourceRoot":"","sources":["../../src/types/overlays.types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACnE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAEhE;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,IAAI,CAAC,EAAE,mBAAmB,CAAC;IAE3B;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;;OAGG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IAEf;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;OAGG;IACH,MAAM,CAAC,EAAE,KAAK,CAAC;IAEf;;;OAGG;IACH,YAAY,CAAC,EAAE,KAAK,CAAC;IAErB;;OAEG;IACH,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAE3B;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IAErB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IAEzB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IAEpB;;OAEG;IACH,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;CACtD;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,MAAM,EAAE,MAAM,EAAE,CAAC;IAEjB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,KAAK,CAAC,EAAE,UAAU,CAAC;IAEnB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,MAAM,CAAC,EAAE,UAAU,EAAE,CAAC;IAEtB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;OAEG;IACH,MAAM,EAAE,MAAM,EAAE,CAAC;IAEjB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,WAAW,CAAC,EAAE,UAAU,CAAC;IAEzB;;OAEG;IACH,SAAS,CAAC,EAAE,UAAU,CAAC;IAEvB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,WAAW,CAAC,EAAE,UAAU,CAAC;IAEzB;;OAEG;IACH,SAAS,CAAC,EAAE,UAAU,CAAC;IAEvB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;OAEG;IACH,IAAI,EAAE,MAAM,EAAE,CAAC;IAEf;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,cAAe,SAAQ,MAAM;IAC5C;;OAEG;IACH,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAErB;;OAEG;IACH,IAAI,CAAC,EAAE,GAAG,CAAC;CACZ;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,KAAK,EAAE,cAAc,EAAE,CAAC;IAExB;;OAEG;IACH,IAAI,CAAC,EAAE,mBAAmB,CAAC;IAE3B;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,WAAW,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,cAAc,CAAA;SAAE,CAAA;KAAE,KAAK,IAAI,CAAC;CACrF;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;IAEX;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,UAAU,CAAC,EAAE,GAAG,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,YAAY,CAAC,EAAE,SAAS,CAAC;IAEzB;;OAEG;IACH,gBAAgB,CAAC,EAAE,SAAS,CAAC;IAE7B;;OAEG;IACH,MAAM,EAAE,YAAY,EAAE,CAAC;IAEvB;;OAEG;IACH,YAAY,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,KAAK,CAAC,SAAS,CAAC;IAEtD;;OAEG;IACH,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,KAAK,CAAC,SAAS,CAAC;IAE3D;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAAC;CAC3C"}
1
+ {"version":3,"file":"overlays.types.d.ts","sourceRoot":"","sources":["../../src/types/overlays.types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"overlays.types.js","sourceRoot":"","sources":["../../src/types/overlays.types.ts"],"names":[],"mappings":"AAAA;;;GAGG","sourcesContent":["/**\n * 高德地图覆盖物相关类型定义\n * 基于 Expo Modules API\n */\n\nimport type { ImageSourcePropType, ViewStyle } from 'react-native';\nimport type { ColorValue, LatLng, Point } from './common.types';\n\n/**\n * 标记点属性\n */\nexport interface MarkerProps {\n /**\n * 坐标\n */\n position: LatLng;\n\n /**\n * 图标\n */\n icon?: ImageSourcePropType;\n\n /**\n * 标题\n */\n title?: string;\n\n /**\n * 描述\n */\n snippet?: string;\n\n /**\n * 透明度 [0, 1]\n * @platform android\n */\n opacity?: number;\n\n /**\n * 是否可拖拽\n */\n draggable?: boolean;\n\n /**\n * 是否平贴地图\n * @platform android\n */\n flat?: boolean;\n\n /**\n * 层级\n */\n zIndex?: number;\n\n /**\n * 覆盖物锚点比例\n * @platform android\n */\n anchor?: Point;\n\n /**\n * 覆盖物偏移位置\n * @platform ios\n */\n centerOffset?: Point;\n\n /**\n * 自定义视图\n */\n children?: React.ReactNode;\n\n /**\n * 点击事件\n */\n onPress?: () => void;\n\n /**\n * 拖拽开始事件\n */\n onDragStart?: () => void;\n\n /**\n * 拖拽中事件\n */\n onDrag?: () => void;\n\n /**\n * 拖拽结束事件\n */\n onDragEnd?: (event: { nativeEvent: LatLng }) => void;\n}\n\n/**\n * 折线属性\n */\nexport interface PolylineProps {\n /**\n * 节点坐标数组\n */\n points: LatLng[];\n\n /**\n * 线宽\n */\n width?: number;\n\n /**\n * 线条颜色\n */\n color?: ColorValue;\n\n /**\n * 层级\n */\n zIndex?: number;\n\n /**\n * 分段颜色\n */\n colors?: ColorValue[];\n\n /**\n * 是否使用渐变色\n */\n gradient?: boolean;\n\n /**\n * 是否绘制大地线\n */\n geodesic?: boolean;\n\n /**\n * 是否绘制虚线\n */\n dotted?: boolean;\n\n /**\n * 点击事件\n */\n onPress?: () => void;\n}\n\n/**\n * 多边形属性\n */\nexport interface PolygonProps {\n /**\n * 节点坐标数组\n */\n points: LatLng[];\n\n /**\n * 边线宽度\n */\n strokeWidth?: number;\n\n /**\n * 边线颜色\n */\n strokeColor?: ColorValue;\n\n /**\n * 填充颜色\n */\n fillColor?: ColorValue;\n\n /**\n * 层级\n */\n zIndex?: number;\n\n /**\n * 点击事件\n */\n onPress?: () => void;\n}\n\n/**\n * 圆形属性\n */\nexport interface CircleProps {\n /**\n * 圆心坐标\n */\n center: LatLng;\n\n /**\n * 半径(米)\n */\n radius: number;\n\n /**\n * 边线宽度\n */\n strokeWidth?: number;\n\n /**\n * 边线颜色\n */\n strokeColor?: ColorValue;\n\n /**\n * 填充颜色\n */\n fillColor?: ColorValue;\n\n /**\n * 层级\n */\n zIndex?: number;\n\n /**\n * 点击事件\n */\n onPress?: () => void;\n}\n\n/**\n * 热力图属性\n */\nexport interface HeatMapProps {\n /**\n * 热力点数据\n */\n data: LatLng[];\n\n /**\n * 热力半径(米)\n */\n radius?: number;\n\n /**\n * 透明度 [0, 1]\n */\n opacity?: number;\n}\n\n/**\n * 海量点标记项\n */\nexport interface MultiPointItem extends LatLng {\n /**\n * 唯一标识\n */\n id?: string | number;\n\n /**\n * 自定义数据\n */\n data?: any;\n}\n\n/**\n * 海量点属性\n */\nexport interface MultiPointProps {\n /**\n * 点集合\n */\n items: MultiPointItem[];\n\n /**\n * 图标\n */\n icon?: ImageSourcePropType;\n\n /**\n * 点击事件\n */\n onPress?: (event: { nativeEvent: { index: number; item: MultiPointItem } }) => void;\n}\n\n/**\n * 聚合点参数\n */\nexport interface ClusterParams {\n /**\n * 唯一标识\n */\n id: number;\n\n /**\n * 包含的标记点数量\n */\n count: number;\n\n /**\n * 聚合点坐标\n */\n position: LatLng;\n}\n\n/**\n * 聚合点项\n */\nexport interface ClusterPoint {\n /**\n * 坐标\n */\n position: LatLng;\n\n /**\n * 自定义数据\n */\n properties?: any;\n}\n\n/**\n * 聚合图层属性\n */\nexport interface ClusterProps {\n /**\n * 聚合半径\n */\n radius?: number;\n\n /**\n * 聚合点样式\n */\n clusterStyle?: ViewStyle;\n\n /**\n * 聚合点文本样式\n */\n clusterTextStyle?: ViewStyle;\n\n /**\n * 坐标点列表\n */\n points: ClusterPoint[];\n\n /**\n * 渲染标记点\n */\n renderMarker: (item: ClusterPoint) => React.ReactNode;\n\n /**\n * 渲染聚合点\n */\n renderCluster?: (params: ClusterParams) => React.ReactNode;\n\n /**\n * 聚合点点击事件\n */\n onPress?: (params: ClusterParams) => void;\n}\n"]}
1
+ {"version":3,"file":"overlays.types.js","sourceRoot":"","sources":["../../src/types/overlays.types.ts"],"names":[],"mappings":"AAAA;;;GAGG","sourcesContent":["/**\n * 高德地图覆盖物相关类型定义\n * 基于 Expo Modules API\n */\n\nimport type { ImageSourcePropType, ViewStyle } from 'react-native';\nimport type { ColorValue, LatLng, Point } from './common.types';\n\n/**\n * 标记点属性\n */\nexport interface MarkerProps {\n /**\n * 坐标\n */\n position: LatLng;\n\n /**\n * 图标\n */\n icon?: ImageSourcePropType;\n\n /**\n * 标题\n */\n title?: string;\n\n /**\n * 描述\n */\n snippet?: string;\n\n /**\n * 透明度 [0, 1]\n * @platform android\n */\n opacity?: number;\n\n /**\n * 是否可拖拽\n */\n draggable?: boolean;\n\n /**\n * 是否平贴地图\n * @platform android\n */\n flat?: boolean;\n\n /**\n * 层级\n */\n zIndex?: number;\n\n /**\n * 覆盖物锚点比例\n * @platform android\n */\n anchor?: Point;\n\n /**\n * 覆盖物偏移位置\n * @platform ios\n */\n centerOffset?: Point;\n\n /**\n * 自定义视图\n */\n children?: React.ReactNode;\n\n /**\n * 点击事件\n */\n onPress?: () => void;\n\n /**\n * 拖拽开始事件\n */\n onDragStart?: () => void;\n\n /**\n * 拖拽中事件\n */\n onDrag?: () => void;\n\n /**\n * 拖拽结束事件\n */\n onDragEnd?: (event: { nativeEvent: LatLng }) => void;\n}\n\n/**\n * 折线属性\n */\nexport interface PolylineProps {\n /**\n * 节点坐标数组\n */\n points: LatLng[];\n\n /**\n * 线宽\n */\n width?: number;\n\n /**\n * 线条颜色\n */\n color?: ColorValue;\n\n /**\n * 层级\n */\n zIndex?: number;\n\n /**\n * 分段颜色\n */\n colors?: ColorValue[];\n\n /**\n * 是否使用渐变色\n */\n gradient?: boolean;\n\n /**\n * 是否绘制大地线\n */\n geodesic?: boolean;\n\n /**\n * 是否绘制虚线\n */\n dotted?: boolean;\n\n /**\n * 纹理图片\n * 支持网络图片(http/https)、本地文件(file://)或资源名称\n */\n texture?: string;\n\n /**\n * 点击事件\n */\n onPress?: () => void;\n}\n\n/**\n * 多边形属性\n */\nexport interface PolygonProps {\n /**\n * 节点坐标数组\n */\n points: LatLng[];\n\n /**\n * 边线宽度\n */\n strokeWidth?: number;\n\n /**\n * 边线颜色\n */\n strokeColor?: ColorValue;\n\n /**\n * 填充颜色\n */\n fillColor?: ColorValue;\n\n /**\n * 层级\n */\n zIndex?: number;\n\n /**\n * 点击事件\n */\n onPress?: () => void;\n}\n\n/**\n * 圆形属性\n */\nexport interface CircleProps {\n /**\n * 圆心坐标\n */\n center: LatLng;\n\n /**\n * 半径(米)\n */\n radius: number;\n\n /**\n * 边线宽度\n */\n strokeWidth?: number;\n\n /**\n * 边线颜色\n */\n strokeColor?: ColorValue;\n\n /**\n * 填充颜色\n */\n fillColor?: ColorValue;\n\n /**\n * 层级\n */\n zIndex?: number;\n\n /**\n * 点击事件\n */\n onPress?: () => void;\n}\n\n/**\n * 热力图属性\n */\nexport interface HeatMapProps {\n /**\n * 热力点数据\n */\n data: LatLng[];\n\n /**\n * 热力半径(米)\n */\n radius?: number;\n\n /**\n * 透明度 [0, 1]\n */\n opacity?: number;\n}\n\n/**\n * 海量点标记项\n */\nexport interface MultiPointItem extends LatLng {\n /**\n * 唯一标识\n */\n id?: string | number;\n\n /**\n * 自定义数据\n */\n data?: any;\n}\n\n/**\n * 海量点属性\n */\nexport interface MultiPointProps {\n /**\n * 点集合\n */\n items: MultiPointItem[];\n\n /**\n * 图标\n */\n icon?: ImageSourcePropType;\n\n /**\n * 点击事件\n */\n onPress?: (event: { nativeEvent: { index: number; item: MultiPointItem } }) => void;\n}\n\n/**\n * 聚合点参数\n */\nexport interface ClusterParams {\n /**\n * 唯一标识\n */\n id: number;\n\n /**\n * 包含的标记点数量\n */\n count: number;\n\n /**\n * 聚合点坐标\n */\n position: LatLng;\n}\n\n/**\n * 聚合点项\n */\nexport interface ClusterPoint {\n /**\n * 坐标\n */\n position: LatLng;\n\n /**\n * 自定义数据\n */\n properties?: any;\n}\n\n/**\n * 聚合图层属性\n */\nexport interface ClusterProps {\n /**\n * 聚合半径\n */\n radius?: number;\n\n /**\n * 聚合点样式\n */\n clusterStyle?: ViewStyle;\n\n /**\n * 聚合点文本样式\n */\n clusterTextStyle?: ViewStyle;\n\n /**\n * 坐标点列表\n */\n points: ClusterPoint[];\n\n /**\n * 渲染标记点\n */\n renderMarker: (item: ClusterPoint) => React.ReactNode;\n\n /**\n * 渲染聚合点\n */\n renderCluster?: (params: ClusterParams) => React.ReactNode;\n\n /**\n * 聚合点点击事件\n */\n onPress?: (params: ClusterParams) => void;\n}\n"]}
package/docs/EXAMPLES.md CHANGED
@@ -339,7 +339,7 @@ await mapRef.current?.removeMarker('marker1');
339
339
 
340
340
  ### Polyline (折线)
341
341
 
342
- **声明式用法:**
342
+ **声明式用法 - 普通折线:**
343
343
  ```tsx
344
344
  <MapView style={{ flex: 1 }}>
345
345
  <Polyline
@@ -348,25 +348,86 @@ await mapRef.current?.removeMarker('marker1');
348
348
  { latitude: 39.95, longitude: 116.45 },
349
349
  { latitude: 40.0, longitude: 116.5 },
350
350
  ]}
351
- strokeWidth={5}
352
- strokeColor="#FF0000FF"
351
+ width={5}
352
+ color="#FFFF0000"
353
353
  onPress={() => console.log('点击折线')}
354
354
  />
355
355
  </MapView>
356
356
  ```
357
357
 
358
+ **声明式用法 - 纹理折线:**
359
+ ```tsx
360
+ import { Image } from 'react-native';
361
+
362
+ const iconUri = Image.resolveAssetSource(require('./assets/arrow.png')).uri;
363
+
364
+ <MapView style={{ flex: 1 }}>
365
+ <Polyline
366
+ points={[
367
+ { latitude: 39.9, longitude: 116.4 },
368
+ { latitude: 39.95, longitude: 116.45 },
369
+ { latitude: 40.0, longitude: 116.5 },
370
+ ]}
371
+ width={20}
372
+ color="#FFFF0000"
373
+ texture={iconUri}
374
+ onPress={() => console.log('点击纹理折线')}
375
+ />
376
+ </MapView>
377
+ ```
378
+
358
379
  **命令式用法:**
359
380
  ```tsx
381
+ // 普通折线
360
382
  await mapRef.current?.addPolyline('polyline1', {
361
383
  points: [
362
384
  { latitude: 39.9, longitude: 116.4 },
363
385
  { latitude: 40.0, longitude: 116.5 },
364
386
  ],
365
- strokeWidth: 5,
366
- strokeColor: 0xFFFF0000,
387
+ width: 5,
388
+ color: '#FFFF0000',
389
+ });
390
+
391
+ // 纹理折线
392
+ await mapRef.current?.addPolyline('polyline2', {
393
+ points: [
394
+ { latitude: 39.9, longitude: 116.4 },
395
+ { latitude: 40.0, longitude: 116.5 },
396
+ ],
397
+ width: 20,
398
+ color: '#FFFF0000',
399
+ texture: iconUri,
400
+ });
401
+
402
+ // 分段纹理示例(使用多个 Polyline)
403
+ const point1 = { latitude: 39.9, longitude: 116.4 };
404
+ const point2 = { latitude: 39.95, longitude: 116.45 };
405
+ const point3 = { latitude: 40.0, longitude: 116.5 };
406
+
407
+ // 第一段:红色箭头
408
+ await mapRef.current?.addPolyline('segment1', {
409
+ points: [point1, point2],
410
+ width: 20,
411
+ color: '#FFFF0000',
412
+ texture: redArrowUri,
413
+ });
414
+
415
+ // 第二段:蓝色箭头
416
+ await mapRef.current?.addPolyline('segment2', {
417
+ points: [point2, point3],
418
+ width: 20,
419
+ color: '#FF0000FF',
420
+ texture: blueArrowUri,
367
421
  });
368
422
  ```
369
423
 
424
+ > **注意**:
425
+ > - 颜色格式使用 ARGB(`#AARRGGBB`),例如 `#FFFF0000` 表示不透明红色
426
+ > - `texture` 支持网络图片(http/https)和本地文件(file://)
427
+ > - 纹理图片会沿着折线方向平铺显示
428
+ > - 建议纹理折线使用较大的 `width` 值(如 20)以获得更好的显示效果
429
+ > - **分段纹理限制**:单个 Polyline 只能设置一个纹理。如需不同线段使用不同纹理,请创建多个 Polyline 组件
430
+
370
431
  ### Polygon (多边形)
371
432
 
372
433
  **声明式用法:**
@@ -371,6 +371,10 @@ public class ExpoGaodeMapModule: Module {
371
371
  Prop("strokeColor") { (view: PolylineView, color: Int) in
372
372
  view.setStrokeColor(color)
373
373
  }
374
+
375
+ Prop("texture") { (view: PolylineView, url: String?) in
376
+ view.setTexture(url)
377
+ }
374
378
  }
375
379
 
376
380
  // Polygon - 多边形
@@ -67,26 +67,33 @@ class OverlayManager {
67
67
  // MARK: - Polyline
68
68
 
69
69
  func addPolyline(id: String, props: [String: Any]) {
70
+ print("📏 OverlayManager.addPolyline - id: \(id), props: \(props)")
71
+
70
72
  guard let mapView = mapView,
71
- let points = props["points"] as? [[String: Double]] else { return }
73
+ let points = props["points"] as? [[String: Double]] else {
74
+ print("❌ OverlayManager.addPolyline - mapView 或 points 为空")
75
+ return
76
+ }
77
+
72
78
  var coordinates: [CLLocationCoordinate2D] = []
73
79
  for point in points {
74
80
  guard let lat = point["latitude"], let lng = point["longitude"] else { continue }
75
81
  coordinates.append(CLLocationCoordinate2D(latitude: lat, longitude: lng))
76
82
  }
77
- guard !coordinates.isEmpty else { return }
83
+ guard coordinates.count >= 2 else {
84
+ print("❌ OverlayManager.addPolyline - 坐标点数量不足: \(coordinates.count)")
85
+ return
86
+ }
78
87
 
79
- let polyline = MAMultiPolyline()
80
- polyline.setPolylineWithCoordinates(&coordinates, count: coordinates.count)
88
+ let polyline = MAPolyline(coordinates: &coordinates, count: UInt(coordinates.count))!
81
89
 
90
+ // 先保存样式和 overlay,再添加到地图
82
91
  overlayStyles[id] = props
83
92
  overlays[id] = polyline
84
- mapView.add(polyline)
85
93
 
86
- // 强制刷新地图渲染
87
- DispatchQueue.main.async {
88
- mapView.setNeedsDisplay()
89
- }
94
+ print("✅ OverlayManager.addPolyline - 准备添加到地图,id: \(id)")
95
+ mapView.add(polyline)
96
+ print("✅ OverlayManager.addPolyline - 已添加到地图")
90
97
  }
91
98
 
92
99
  func removePolyline(id: String) {
@@ -154,26 +161,43 @@ class OverlayManager {
154
161
  }
155
162
 
156
163
  return renderer
157
- } else if let polyline = overlay as? MAMultiPolyline {
158
- let renderer = MAMultiColoredPolylineRenderer(multiPolyline: polyline)
164
+ } else if let polyline = overlay as? MAPolyline {
165
+ let renderer = MAPolylineRenderer(polyline: polyline)!
159
166
 
160
- if let color = style?["color"] {
161
- renderer?.strokeColor = ColorParser.parseColor(color) ?? .red
162
- } else if let strokeColor = style?["strokeColor"] {
163
- renderer?.strokeColor = ColorParser.parseColor(strokeColor) ?? .red
167
+ // 设置线宽
168
+ if let width = style?["width"] as? Double {
169
+ renderer.lineWidth = CGFloat(width)
170
+ } else if let strokeWidth = style?["strokeWidth"] as? Double {
171
+ renderer.lineWidth = CGFloat(strokeWidth)
164
172
  } else {
165
- renderer?.strokeColor = .red
173
+ renderer.lineWidth = 8
166
174
  }
167
175
 
168
- if let width = style?["width"] as? Double {
169
- renderer?.lineWidth = CGFloat(width)
170
- } else if let strokeWidth = style?["strokeWidth"] as? Double {
171
- renderer?.lineWidth = CGFloat(strokeWidth)
176
+ // 设置线条样式
177
+ renderer.lineJoinType = kMALineJoinRound
178
+ renderer.lineCapType = kMALineCapRound
179
+
180
+ // 设置纹理或颜色
181
+ if let textureUrl = style?["texture"] as? String, !textureUrl.isEmpty {
182
+ loadPolylineTexture(url: textureUrl, renderer: renderer)
172
183
  } else {
173
- renderer?.lineWidth = 5
184
+ if let color = style?["color"] {
185
+ print("🎨 color 原始值: \(color), 类型: \(type(of: color))")
186
+ let parsedColor = ColorParser.parseColor(color)
187
+ print("🎨 解析后的颜色: \(String(describing: parsedColor))")
188
+ renderer.strokeColor = parsedColor ?? .red
189
+ } else if let strokeColor = style?["strokeColor"] {
190
+ print("🎨 strokeColor 原始值: \(strokeColor), 类型: \(type(of: strokeColor))")
191
+ let parsedColor = ColorParser.parseColor(strokeColor)
192
+ print("🎨 解析后的颜色: \(String(describing: parsedColor))")
193
+ renderer.strokeColor = parsedColor ?? .red
194
+ } else {
195
+ print("⚠️ 没有找到 color 或 strokeColor,使用默认红色")
196
+ renderer.strokeColor = .red
197
+ }
174
198
  }
175
199
 
176
- return renderer!
200
+ return renderer
177
201
  } else if let polygon = overlay as? MAPolygon {
178
202
  guard let renderer = MAPolygonRenderer(polygon: polygon) else {
179
203
  return nil
@@ -195,6 +219,48 @@ class OverlayManager {
195
219
  return nil
196
220
  }
197
221
 
222
+ private func loadPolylineTexture(url: String, renderer: MAPolylineRenderer) {
223
+ if url.hasPrefix("http://") || url.hasPrefix("https://") {
224
+ guard let imageUrl = URL(string: url) else {
225
+ print("❌ OverlayManager: 无效的 URL: \(url)")
226
+ return
227
+ }
228
+ URLSession.shared.dataTask(with: imageUrl) { [weak self] data, _, error in
229
+ if let error = error {
230
+ print("❌ OverlayManager: 下载图片失败: \(error)")
231
+ return
232
+ }
233
+ guard let data = data, let image = UIImage(data: data) else {
234
+ print("❌ OverlayManager: 无法创建图片")
235
+ return
236
+ }
237
+ print("✅ OverlayManager: 图片下载成功,大小: \(image.size)")
238
+ DispatchQueue.main.async {
239
+ self?.applyPolylineTexture(image: image, to: renderer)
240
+ }
241
+ }.resume()
242
+ } else if url.hasPrefix("file://") {
243
+ let path = String(url.dropFirst(7))
244
+ if let image = UIImage(contentsOfFile: path) {
245
+ print("✅ OverlayManager: 本地图片加载成功")
246
+ applyPolylineTexture(image: image, to: renderer)
247
+ } else {
248
+ print("❌ OverlayManager: 本地图片加载失败: \(path)")
249
+ }
250
+ } else {
251
+ if let image = UIImage(named: url) {
252
+ print("✅ OverlayManager: 资源图片加载成功")
253
+ applyPolylineTexture(image: image, to: renderer)
254
+ } else {
255
+ print("❌ OverlayManager: 资源图片加载失败: \(url)")
256
+ }
257
+ }
258
+ }
259
+
260
+ private func applyPolylineTexture(image: UIImage, to renderer: MAPolylineRenderer) {
261
+ renderer.strokeImage = image
262
+ }
263
+
198
264
  func clear() {
199
265
  guard let mapView = mapView else { return }
200
266
  for overlay in overlays.values {
@@ -207,4 +273,4 @@ class OverlayManager {
207
273
  overlayStyles.removeAll()
208
274
  annotations.removeAll()
209
275
  }
210
- }
276
+ }
@@ -5,6 +5,7 @@ class PolylineView: ExpoView {
5
5
  var points: [[String: Double]] = []
6
6
  var strokeWidth: Float = 0
7
7
  var strokeColor: Any?
8
+ var textureUrl: String?
8
9
 
9
10
  private var mapView: MAMapView?
10
11
  var polyline: MAPolyline?
@@ -36,12 +37,67 @@ class PolylineView: ExpoView {
36
37
  func getRenderer() -> MAOverlayRenderer {
37
38
  if renderer == nil, let polyline = polyline {
38
39
  renderer = MAPolylineRenderer(polyline: polyline)
39
- renderer?.strokeColor = ColorParser.parseColor(strokeColor) ?? UIColor.clear
40
40
  renderer?.lineWidth = CGFloat(strokeWidth)
41
+
42
+ if let url = textureUrl {
43
+ print("🎨 PolylineView: 加载纹理 URL: \(url)")
44
+ loadTexture(url: url, renderer: renderer!)
45
+ } else {
46
+ renderer?.strokeColor = ColorParser.parseColor(strokeColor) ?? UIColor.clear
47
+ }
41
48
  }
42
49
  return renderer!
43
50
  }
44
51
 
52
+ private func loadTexture(url: String, renderer: MAPolylineRenderer) {
53
+ if url.hasPrefix("http://") || url.hasPrefix("https://") {
54
+ guard let imageUrl = URL(string: url) else {
55
+ print("❌ PolylineView: 无效的 URL: \(url)")
56
+ return
57
+ }
58
+ URLSession.shared.dataTask(with: imageUrl) { [weak self] data, _, error in
59
+ if let error = error {
60
+ print("❌ PolylineView: 下载图片失败: \(error)")
61
+ return
62
+ }
63
+ guard let data = data, let image = UIImage(data: data) else {
64
+ print("❌ PolylineView: 无法创建图片")
65
+ return
66
+ }
67
+ print("✅ PolylineView: 图片下载成功,大小: \(image.size)")
68
+ DispatchQueue.main.async {
69
+ self?.applyTexture(image: image, to: renderer)
70
+ }
71
+ }.resume()
72
+ } else if url.hasPrefix("file://") {
73
+ let path = String(url.dropFirst(7))
74
+ if let image = UIImage(contentsOfFile: path) {
75
+ print("✅ PolylineView: 本地图片加载成功")
76
+ applyTexture(image: image, to: renderer)
77
+ } else {
78
+ print("❌ PolylineView: 本地图片加载失败: \(path)")
79
+ }
80
+ } else {
81
+ if let image = UIImage(named: url) {
82
+ print("✅ PolylineView: 资源图片加载成功")
83
+ applyTexture(image: image, to: renderer)
84
+ } else {
85
+ print("❌ PolylineView: 资源图片加载失败: \(url)")
86
+ }
87
+ }
88
+ }
89
+
90
+ private func applyTexture(image: UIImage, to renderer: MAPolylineRenderer) {
91
+ let selector = NSSelectorFromString("loadStrokeTextureImage:")
92
+ if renderer.responds(to: selector) {
93
+ renderer.perform(selector, with: image)
94
+ print("✅ PolylineView: 纹理已应用")
95
+ mapView?.setNeedsDisplay()
96
+ } else {
97
+ print("❌ PolylineView: renderer 不支持 loadStrokeTextureImage 方法")
98
+ }
99
+ }
100
+
45
101
  func setPoints(_ points: [[String: Double]]) {
46
102
  self.points = points
47
103
  renderer = nil
@@ -59,4 +115,10 @@ class PolylineView: ExpoView {
59
115
  renderer = nil
60
116
  updatePolyline()
61
117
  }
118
+
119
+ func setTexture(_ url: String?) {
120
+ textureUrl = url
121
+ renderer = nil
122
+ updatePolyline()
123
+ }
62
124
  }
@@ -73,18 +73,19 @@ class ColorParser {
73
73
  hex = r + g + b + a
74
74
  }
75
75
 
76
- // 处理 #RRGGBBAA 格式
76
+ // 处理 #AARRGGBB 或 #RRGGBBAA 格式
77
77
  if hex.count == 8 {
78
78
  let scanner = Scanner(string: hex)
79
79
  var hexNumber: UInt64 = 0
80
80
 
81
81
  if scanner.scanHexInt64(&hexNumber) {
82
- let red = CGFloat((hexNumber & 0xff000000) >> 24) / 255
83
- let green = CGFloat((hexNumber & 0x00ff0000) >> 16) / 255
84
- let blue = CGFloat((hexNumber & 0x0000ff00) >> 8) / 255
85
- alpha = CGFloat(hexNumber & 0x000000ff) / 255
82
+ // 尝试 ARGB 格式(Android 风格)
83
+ let alphaARGB = CGFloat((hexNumber & 0xff000000) >> 24) / 255
84
+ let redARGB = CGFloat((hexNumber & 0x00ff0000) >> 16) / 255
85
+ let greenARGB = CGFloat((hexNumber & 0x0000ff00) >> 8) / 255
86
+ let blueARGB = CGFloat(hexNumber & 0x000000ff) / 255
86
87
 
87
- return UIColor(red: red, green: green, blue: blue, alpha: alpha)
88
+ return UIColor(red: redARGB, green: greenARGB, blue: blueARGB, alpha: alphaARGB)
88
89
  }
89
90
  }
90
91
 
@@ -146,7 +147,7 @@ class ColorParser {
146
147
  }
147
148
  }
148
149
 
149
- // UIColor 扩展,支持从数字创建
150
+ // UIColor 扩展,支持从数字创建(ARGB 格式)
150
151
  extension UIColor {
151
152
  convenience init(hex: Int) {
152
153
  let alpha = CGFloat((hex >> 24) & 0xFF) / 255.0
@@ -155,4 +156,9 @@ extension UIColor {
155
156
  let blue = CGFloat(hex & 0xFF) / 255.0
156
157
  self.init(red: red, green: green, blue: blue, alpha: alpha)
157
158
  }
159
+
160
+ // 别名方法,与 hex 功能相同
161
+ convenience init(argb: Int) {
162
+ self.init(hex: argb)
163
+ }
158
164
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-gaode-map",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "一个功能完整的高德地图 React Native 组件库,基于 Expo Modules 开发,提供地图显示、定位、覆盖物等功能。",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -2,7 +2,7 @@
2
2
  * @Author : 尚博信_王强 wangqiang03@sunboxsoft.com
3
3
  * @Date : 2025-11-13 15:01:30
4
4
  * @LastEditors : 尚博信_王强 wangqiang03@sunboxsoft.com
5
- * @LastEditTime : 2025-11-14 15:48:14
5
+ * @LastEditTime : 2025-11-15 01:08:27
6
6
  * @FilePath : /expo-gaode-map/src/components/overlays/Polyline.tsx
7
7
  * @Description : 地图折线组件 - 使用命令式 API
8
8
  *
@@ -32,30 +32,27 @@ import type { PolylineProps } from '../../types';
32
32
  */
33
33
  export default function Polyline(props: PolylineProps) {
34
34
  const mapRef = React.useContext(MapContext);
35
- const polylineIdRef = React.useRef<string>(`polyline_${Date.now()}_${Math.random()}`);
36
- const isInitialMount = React.useRef(true);
35
+ const polylineIdRef = React.useRef<string | null>(null);
37
36
 
38
37
  // 添加折线
39
38
  React.useEffect(() => {
40
- const polylineId = polylineIdRef.current;
39
+ const polylineId = `polyline_${Date.now()}_${Math.random()}`;
40
+ polylineIdRef.current = polylineId;
41
41
 
42
- mapRef?.current?.addPolyline?.(polylineId, props);
42
+ // 只传递必要的属性
43
+ const polylineProps = {
44
+ points: props.points,
45
+ width: props.width,
46
+ color: props.color,
47
+ ...(props.texture && { texture: props.texture }),
48
+ };
49
+
50
+ mapRef?.current?.addPolyline?.(polylineId, polylineProps);
43
51
 
44
52
  return () => {
45
53
  mapRef?.current?.removePolyline?.(polylineId);
46
54
  };
47
55
  }, []);
48
56
 
49
- // 监听 Props 变化,更新折线(跳过初始渲染)
50
- React.useEffect(() => {
51
- if (isInitialMount.current) {
52
- isInitialMount.current = false;
53
- return;
54
- }
55
-
56
- const polylineId = polylineIdRef.current;
57
- mapRef?.current?.updatePolyline?.(polylineId, props);
58
- }, [props.points, props.width, props.color]);
59
-
60
57
  return null;
61
58
  }
@@ -134,6 +134,12 @@ export interface PolylineProps {
134
134
  */
135
135
  dotted?: boolean;
136
136
 
137
+ /**
138
+ * 纹理图片
139
+ * 支持网络图片(http/https)、本地文件(file://)或资源名称
140
+ */
141
+ texture?: string;
142
+
137
143
  /**
138
144
  * 点击事件
139
145
  */
@@ -1,11 +0,0 @@
1
- import UIKit
2
-
3
- extension UIColor {
4
- convenience init(argb: Int) {
5
- let alpha = CGFloat((argb >> 24) & 0xFF) / 255.0
6
- let red = CGFloat((argb >> 16) & 0xFF) / 255.0
7
- let green = CGFloat((argb >> 8) & 0xFF) / 255.0
8
- let blue = CGFloat(argb & 0xFF) / 255.0
9
- self.init(red: red, green: green, blue: blue, alpha: alpha)
10
- }
11
- }