expo-gaode-map-navigation 1.1.4 → 1.1.5-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.
@@ -4,16 +4,20 @@ import android.annotation.SuppressLint
4
4
  import android.content.Context
5
5
  import android.os.Bundle
6
6
  import android.util.Log
7
+ import android.view.View
8
+ import android.view.ViewGroup
7
9
  import com.amap.api.navi.AMapNavi
8
10
  import com.amap.api.navi.AMapNaviListener
9
11
  import com.amap.api.navi.AMapNaviView
10
12
  import com.amap.api.navi.AMapNaviViewListener
11
13
  import com.amap.api.navi.AMapNaviViewOptions
14
+ import com.amap.api.navi.enums.MapStyle
12
15
  import com.amap.api.navi.enums.NaviType
13
16
  import com.amap.api.navi.model.*
14
17
  import expo.modules.kotlin.AppContext
15
18
  import expo.modules.kotlin.viewevent.EventDispatcher
16
19
  import expo.modules.kotlin.views.ExpoView
20
+ import java.util.IdentityHashMap
17
21
 
18
22
  @SuppressLint("ViewConstructor")
19
23
  @Suppress("DEPRECATION", "OVERRIDE_DEPRECATION")
@@ -38,11 +42,37 @@ class ExpoGaodeMapNaviView(context: Context, appContext: AppContext) : ExpoView(
38
42
  internal var showCamera: Boolean = true
39
43
  internal var naviType: Int = NaviType.GPS
40
44
  internal var enableVoice: Boolean = true
41
-
45
+
46
+
47
+ internal var androidStatusBarPaddingTopDp: Double? = null
48
+
49
+ internal var showUIElements: Boolean = true
50
+ internal var androidTrafficBarEnabled: Boolean = true
51
+ internal var isRouteListButtonShow: Boolean = true
52
+ internal var isTrafficLayerEnabled: Boolean = true
53
+ internal var autoChangeZoom : Boolean = true
54
+ internal var autoLockCar: Boolean = true
55
+ internal var isTrafficLine: Boolean = true
56
+ internal var isRealCrossDisplayShow : Boolean = true
57
+ internal var isNaviArrowVisible : Boolean = true
58
+ internal var isAfterRouteAutoGray: Boolean = false
59
+ internal var isVectorLineShow: Boolean = true
60
+ internal var isNaviTravelView : Boolean = false
42
61
  private val naviView: AMapNaviView = AMapNaviView(context)
43
62
  private var aMapNavi: AMapNavi? = null
44
63
  private var startCoordinate: NaviLatLng? = null
45
64
  private var endCoordinate: NaviLatLng? = null
65
+
66
+ private var lastAppliedTopPaddingPx: Int? = null
67
+
68
+ private var topInsetPx: Int = 0
69
+ private var overlayHooked: Boolean = false
70
+ private val overlayStates = IdentityHashMap<View, OverlayState>()
71
+
72
+ private data class OverlayState(
73
+ val translationY: Float,
74
+ val paddingTop: Int
75
+ )
46
76
 
47
77
  // 导航监听器
48
78
  @Suppress("DEPRECATION", "OVERRIDE_DEPRECATION")
@@ -270,7 +300,18 @@ class ExpoGaodeMapNaviView(context: Context, appContext: AppContext) : ExpoView(
270
300
  try {
271
301
  // 初始化导航视图
272
302
  naviView.onCreate(Bundle())
303
+ naviView.layoutParams = android.widget.FrameLayout.LayoutParams(
304
+ android.widget.FrameLayout.LayoutParams.MATCH_PARENT,
305
+ android.widget.FrameLayout.LayoutParams.MATCH_PARENT
306
+ )
273
307
  addView(naviView)
308
+
309
+ clipChildren = false
310
+ clipToPadding = false
311
+ naviView.clipChildren = false
312
+ naviView.clipToPadding = false
313
+
314
+ ensureOverlayInsetHook()
274
315
 
275
316
  // 使用单例获取导航实例
276
317
  aMapNavi = AMapNavi.getInstance(context.applicationContext)
@@ -278,27 +319,28 @@ class ExpoGaodeMapNaviView(context: Context, appContext: AppContext) : ExpoView(
278
319
 
279
320
  // 使用内置语音播报功能(v5.6.0+)
280
321
  aMapNavi?.setUseInnerVoice(true, true) // 启用内置语音,并回调文字
281
-
322
+ //设置是否为骑步行视图
323
+ aMapNavi?.isNaviTravelView = isNaviTravelView
282
324
  // 设置导航视图选项 - 根据 AMapNaviViewOptions API
283
325
  val options = AMapNaviViewOptions()
284
326
 
285
327
  // === 基础界面控制 ===
286
328
  // 注意:isLayoutVisible 控制整个导航UI布局的显示
287
329
  // 设置为 true 将显示导航信息面板(包括距离、时间等)
288
- options.isLayoutVisible = true // ⭐ 显示导航界面布局(包括导航信息面板)
330
+ options.isLayoutVisible = showUIElements
289
331
  options.isSettingMenuEnabled = true // 显示设置菜单按钮
290
332
  options.isCompassEnabled = true // 显示指南针
291
- options.isTrafficBarEnabled = true // 显示交通路况光柱条(顶部)
292
- options.isRouteListButtonShow = true // 显示路线全览按钮
293
-
333
+ options.isTrafficBarEnabled = androidTrafficBarEnabled // 显示路况条
334
+ options.isRouteListButtonShow = isRouteListButtonShow // 显示路线全览按钮
335
+
294
336
  Log.d("ExpoGaodeMapNaviView", "导航UI配置: isLayoutVisible=true, 所有UI元素已启用")
295
337
 
296
338
  // === 地图图层 ===
297
- options.isTrafficLayerEnabled = true // 显示交通路况图层
298
- options.isTrafficLine = true // 显示交通路况线
339
+ options.isTrafficLayerEnabled = isTrafficLayerEnabled // 显示交通路况图层
340
+ options.isTrafficLine = isTrafficLine // 显示交通路况线
299
341
 
300
342
  // === 路口放大图和车道信息 ===
301
- options.isRealCrossDisplayShow = true // 显示实景路口放大图
343
+ options.isRealCrossDisplayShow = isRealCrossDisplayShow // 显示实景路口放大图
302
344
  options.setModeCrossDisplayShow(true) // 显示路口3D模型(使用方法而非属性)
303
345
  options.isLaneInfoShow = true // 显示车道信息
304
346
  options.isEyrieCrossDisplay = true // 显示鹰眼路口图
@@ -310,32 +352,36 @@ class ExpoGaodeMapNaviView(context: Context, appContext: AppContext) : ExpoView(
310
352
 
311
353
  // === 路线和导航箭头 ===
312
354
  options.isAutoDrawRoute = true // 自动绘制路线
313
- options.isNaviArrowVisible = true // 显示导航箭头
355
+ options.isNaviArrowVisible = isNaviArrowVisible // 显示导航箭头
314
356
  options.isSecondActionVisible = true // 显示辅助操作(如下个路口提示)
315
357
  options.isDrawBackUpOverlay = true // 绘制备用路线覆盖物
358
+ if(isVectorLineShow)
359
+ options.isLeaderLineEnabled
316
360
 
317
361
  // === 地图锁车和视角控制 ===
318
- options.isAutoLockCar = true // 自动锁车
362
+ options.isAutoLockCar = autoLockCar // 自动锁车
319
363
  options.lockMapDelayed = 5000L // 5秒后自动锁车(毫秒)
320
- options.setAutoDisplayOverview(false) // 不自动显示全览
321
- options.isAutoChangeZoom = true // 根据导航自动调整缩放级别
322
- options.setZoom(18) // 锁车时的缩放级别 (14-18)
323
- options.setTilt(35) // 锁车时的倾斜角度 (0-60)
364
+ options.isAutoDisplayOverview = false // 不自动显示全览
365
+ options.isAutoChangeZoom = autoChangeZoom // 根据导航自动调整缩放级别
366
+ options.zoom = 18 // 锁车时的缩放级别 (14-18)
367
+ options.tilt = 35 // 锁车时的倾斜角度 (0-60)
324
368
 
325
369
  // === 已走路线处理 ===
326
- options.setAfterRouteAutoGray(true) // 走过的路线自动变灰
370
+ options.isAfterRouteAutoGray = isAfterRouteAutoGray // 走过的路线自动变灰
327
371
 
328
372
  // === 传感器和定位 ===
329
- options.setSensorEnable(true) // 使用设备传感器
373
+ options.isSensorEnable = true // 使用设备传感器
330
374
 
331
375
  // === 夜间模式(已废弃但保留兼容) ===
332
376
  // 建议使用 setMapStyle 方法设置地图样式
333
- options.setAutoNaviViewNightMode(false) // 不自动切换夜间模式
377
+ options.isAutoNaviViewNightMode = false // 不自动切换夜间模式
334
378
 
335
379
  // === 鹰眼地图 ===
336
- options.setEagleMapVisible(false) // 不显示鹰眼地图(小地图)
380
+ options.isEagleMapVisible = false // 不显示鹰眼地图(小地图)
337
381
 
338
382
  naviView.viewOptions = options
383
+
384
+ naviView.post { updateTopInsetPadding() }
339
385
 
340
386
  // 设置导航视图监听器
341
387
  naviView.setAMapNaviViewListener(object : AMapNaviViewListener {
@@ -364,6 +410,323 @@ class ExpoGaodeMapNaviView(context: Context, appContext: AppContext) : ExpoView(
364
410
  }
365
411
  }
366
412
 
413
+ private fun getStatusBarHeightPx(): Int {
414
+ return try {
415
+ val resourceId = context.resources.getIdentifier("status_bar_height", "dimen", "android")
416
+ if (resourceId > 0) context.resources.getDimensionPixelSize(resourceId) else 0
417
+ } catch (_: Exception) {
418
+ 0
419
+ }
420
+ }
421
+
422
+ private fun dpToPx(dp: Double): Int {
423
+ val density = context.resources.displayMetrics.density
424
+ return (dp * density + 0.5).toInt()
425
+ }
426
+
427
+ private fun updateTopInsetPadding() {
428
+ val shouldApplyPadding = androidStatusBarPaddingTopDp != null
429
+ val paddingTopPx = if (shouldApplyPadding) {
430
+ androidStatusBarPaddingTopDp?.let { dpToPx(it) } ?: getStatusBarHeightPx()
431
+ } else {
432
+ //默认返回状态栏高度
433
+ getStatusBarHeightPx()
434
+ }
435
+
436
+ if (lastAppliedTopPaddingPx == paddingTopPx) {
437
+ return
438
+ }
439
+
440
+ lastAppliedTopPaddingPx = paddingTopPx
441
+
442
+ topInsetPx = paddingTopPx
443
+
444
+ naviView.setPadding(0, 0, 0, 0)
445
+
446
+ applyTopInsetToOverlays(paddingTopPx)
447
+ }
448
+
449
+ private fun ensureOverlayInsetHook() {
450
+ if (overlayHooked) {
451
+ return
452
+ }
453
+
454
+ overlayHooked = true
455
+ naviView.addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->
456
+ applyTopInsetToOverlays(topInsetPx)
457
+ }
458
+ }
459
+
460
+ private fun applyTopInsetToOverlays(paddingTopPx: Int) {
461
+ if (paddingTopPx <= 0) {
462
+ if (overlayStates.isNotEmpty()) {
463
+ val iterator = overlayStates.entries.iterator()
464
+ while (iterator.hasNext()) {
465
+ val entry = iterator.next()
466
+ val view = entry.key
467
+ val state = entry.value
468
+ view.translationY = state.translationY
469
+ view.setPadding(view.paddingLeft, state.paddingTop, view.paddingRight, view.paddingBottom)
470
+ iterator.remove()
471
+ }
472
+ }
473
+ return
474
+ }
475
+
476
+ val rawTargets = findTopOverlayTargets(naviView)
477
+ val targets = filterTopLevelTargets(naviView, rawTargets)
478
+ if (targets.isEmpty()) {
479
+ val applied = applyTopPaddingToNaviUiLayer(paddingTopPx)
480
+ if (!applied) {
481
+ naviView.post { applyTopPaddingToNaviUiLayer(paddingTopPx) }
482
+ }
483
+ return
484
+ }
485
+
486
+ val targetSet = targets.toHashSet()
487
+
488
+ val iterator = overlayStates.entries.iterator()
489
+ while (iterator.hasNext()) {
490
+ val entry = iterator.next()
491
+ val view = entry.key
492
+ if (!targetSet.contains(view)) {
493
+ val state = entry.value
494
+ view.translationY = state.translationY
495
+ view.setPadding(view.paddingLeft, state.paddingTop, view.paddingRight, view.paddingBottom)
496
+ iterator.remove()
497
+ }
498
+ }
499
+
500
+ for (target in targets) {
501
+ if (!overlayStates.containsKey(target)) {
502
+ overlayStates[target] = OverlayState(
503
+ translationY = target.translationY,
504
+ paddingTop = target.paddingTop
505
+ )
506
+ }
507
+ ensureNoClipChain(target)
508
+ target.translationY = paddingTopPx.toFloat()
509
+ }
510
+ }
511
+
512
+ private fun ensureNoClipChain(view: View) {
513
+ var currentParent = view.parent
514
+ while (currentParent is ViewGroup) {
515
+ currentParent.clipChildren = false
516
+ currentParent.clipToPadding = false
517
+ if (currentParent === naviView) {
518
+ break
519
+ }
520
+ currentParent = currentParent.parent
521
+ }
522
+ }
523
+
524
+ private fun filterTopLevelTargets(root: ViewGroup, targets: List<View>): List<View> {
525
+ if (targets.size <= 1) {
526
+ return targets
527
+ }
528
+
529
+ val set = targets.toHashSet()
530
+ val result = ArrayList<View>(targets.size)
531
+ for (view in targets) {
532
+ var parent = view.parent
533
+ var hasAncestorInTargets = false
534
+ while (parent is View) {
535
+ if (parent === root) {
536
+ break
537
+ }
538
+ if (set.contains(parent)) {
539
+ hasAncestorInTargets = true
540
+ break
541
+ }
542
+ parent = parent.parent
543
+ }
544
+ if (!hasAncestorInTargets) {
545
+ result.add(view)
546
+ }
547
+ }
548
+
549
+ return result
550
+ }
551
+
552
+ private fun findTopOverlayTargets(root: ViewGroup): List<View> {
553
+ val result = ArrayList<View>()
554
+ val parentHeight = root.height
555
+ val parentWidth = root.width
556
+ if (parentHeight <= 0 || parentWidth <= 0) {
557
+ return result
558
+ }
559
+
560
+ val queue = ArrayDeque<View>()
561
+ for (i in 0 until root.childCount) {
562
+ queue.add(root.getChildAt(i))
563
+ }
564
+
565
+ while (queue.isNotEmpty()) {
566
+ val view = queue.removeFirst()
567
+ val group = view as? ViewGroup
568
+ if (group != null) {
569
+ for (i in 0 until group.childCount) {
570
+ queue.add(group.getChildAt(i))
571
+ }
572
+ }
573
+
574
+ if (!view.isShown) {
575
+ continue
576
+ }
577
+
578
+ val name = view.javaClass.name
579
+ if (name.contains("MapView", ignoreCase = true) ||
580
+ name.contains("Texture", ignoreCase = true) ||
581
+ name.contains("Surface", ignoreCase = true) ||
582
+ name.contains("GLSurface", ignoreCase = true)
583
+ ) {
584
+ continue
585
+ }
586
+
587
+ if (view.height <= 0 || view.width <= 0) {
588
+ continue
589
+ }
590
+
591
+ if (view.top > 1) {
592
+ continue
593
+ }
594
+
595
+ if (view.height >= (parentHeight * 0.6f).toInt()) {
596
+ continue
597
+ }
598
+
599
+ val wideEnough = view.width >= (parentWidth * 0.5f).toInt()
600
+ val likelyUi = wideEnough && (view.isClickable || (view as? ViewGroup)?.childCount ?: 0 > 0)
601
+ if (!likelyUi) {
602
+ continue
603
+ }
604
+
605
+ result.add(view)
606
+ }
607
+
608
+ return result
609
+ }
610
+
611
+ private fun applyTopPaddingToNaviUiLayer(paddingTopPx: Int): Boolean {
612
+ val uiRoot = findNaviUiRoot(naviView) ?: return false
613
+
614
+ uiRoot.setPadding(uiRoot.paddingLeft, paddingTopPx, uiRoot.paddingRight, uiRoot.paddingBottom)
615
+ uiRoot.clipToPadding = false
616
+ return true
617
+ }
618
+
619
+ private fun findNaviUiRoot(root: ViewGroup): ViewGroup? {
620
+ var best: ViewGroup? = null
621
+ var bestScore = Int.MIN_VALUE
622
+
623
+ val queue = ArrayDeque<View>()
624
+ for (i in 0 until root.childCount) {
625
+ queue.add(root.getChildAt(i))
626
+ }
627
+
628
+ while (queue.isNotEmpty()) {
629
+ val view = queue.removeFirst()
630
+ val group = view as? ViewGroup
631
+ if (group != null) {
632
+ val score = scoreAsUiRootCandidate(group)
633
+ if (score > bestScore) {
634
+ bestScore = score
635
+ best = group
636
+ }
637
+ for (i in 0 until group.childCount) {
638
+ queue.add(group.getChildAt(i))
639
+ }
640
+ }
641
+ }
642
+
643
+ return if (bestScore > 0) best else null
644
+ }
645
+
646
+ private fun scoreAsUiRootCandidate(group: ViewGroup): Int {
647
+ val name = group.javaClass.name
648
+ if (name.contains("MapView", ignoreCase = true) ||
649
+ name.contains("Texture", ignoreCase = true) ||
650
+ name.contains("Surface", ignoreCase = true) ||
651
+ name.contains("GLSurface", ignoreCase = true)
652
+ ) {
653
+ return Int.MIN_VALUE
654
+ }
655
+
656
+ var score = 0
657
+
658
+ val lp = group.layoutParams
659
+ if (lp != null) {
660
+ if (lp.width == ViewGroup.LayoutParams.MATCH_PARENT && lp.height == ViewGroup.LayoutParams.MATCH_PARENT) {
661
+ score += 4
662
+ } else if (lp.width == ViewGroup.LayoutParams.MATCH_PARENT) {
663
+ score += 2
664
+ }
665
+ }
666
+
667
+ if (group.childCount >= 3) {
668
+ score += 2
669
+ } else if (group.childCount >= 1) {
670
+ score += 1
671
+ }
672
+
673
+ if (name.contains("RelativeLayout", ignoreCase = true) || name.contains("FrameLayout", ignoreCase = true)) {
674
+ score += 1
675
+ }
676
+
677
+ return score
678
+ }
679
+
680
+
681
+
682
+ fun applyAndroidStatusBarPaddingTop(topDp: Double?) {
683
+ androidStatusBarPaddingTopDp = topDp
684
+ updateTopInsetPadding()
685
+ }
686
+
687
+ fun applyShowUIElements(visible: Boolean) {
688
+ showUIElements = visible
689
+ val options = naviView.viewOptions
690
+ options.isLayoutVisible = visible
691
+ naviView.viewOptions = options
692
+ }
693
+
694
+ fun applyAndroidTrafficBarEnabled(enabled: Boolean) {
695
+ androidTrafficBarEnabled = enabled
696
+ val options = naviView.viewOptions
697
+ options.isTrafficBarEnabled = enabled
698
+ naviView.viewOptions = options
699
+ }
700
+
701
+ fun applyShowTrafficButton(enabled: Boolean) {
702
+ isTrafficLayerEnabled = enabled
703
+ val options = naviView.viewOptions
704
+ options.isTrafficLayerEnabled = enabled
705
+ naviView.viewOptions = options
706
+ }
707
+
708
+ fun applyShowBrowseRouteButton(enabled: Boolean) {
709
+ isRouteListButtonShow = enabled
710
+ val options = naviView.viewOptions
711
+ options.isRouteListButtonShow = enabled
712
+ naviView.viewOptions = options
713
+ }
714
+
715
+ fun applyShowGreyAfterPass(enabled: Boolean){
716
+ isAfterRouteAutoGray = enabled
717
+ val options = naviView.viewOptions
718
+ options.isAfterRouteAutoGray = enabled
719
+ naviView.viewOptions = options
720
+ }
721
+
722
+ fun applyShowVectorline(enabled: Boolean){
723
+ isVectorLineShow = enabled
724
+ val options = naviView.viewOptions
725
+ if(enabled)
726
+ options.isLeaderLineEnabled
727
+ naviView.viewOptions = options
728
+ }
729
+
367
730
  fun startNavigation(startLat: Double, startLng: Double, endLat: Double, endLng: Double, promise: expo.modules.kotlin.Promise) {
368
731
  Log.d("ExpoGaodeMapNaviView", "startNavigation: $startLat, $startLng, $endLat, $endLng, naviType: $naviType")
369
732
  try {
@@ -454,24 +817,28 @@ class ExpoGaodeMapNaviView(context: Context, appContext: AppContext) : ExpoView(
454
817
  }
455
818
 
456
819
  fun applyAutoLockCar(enabled: Boolean) {
820
+ autoLockCar = enabled
457
821
  val options = naviView.viewOptions
458
822
  options.isAutoLockCar = enabled
459
823
  naviView.viewOptions = options
460
824
  }
461
825
 
462
826
  fun applyAutoChangeZoom(enabled: Boolean) {
827
+ autoChangeZoom = enabled
463
828
  val options = naviView.viewOptions
464
829
  options.isAutoChangeZoom = enabled
465
830
  naviView.viewOptions = options
466
831
  }
467
832
 
468
833
  fun applyTrafficLayerEnabled(enabled: Boolean) {
834
+ isTrafficLine = enabled
469
835
  val options = naviView.viewOptions
470
- options.isTrafficLayerEnabled = enabled
836
+ options.isTrafficLine = enabled
471
837
  naviView.viewOptions = options
472
838
  }
473
839
 
474
840
  fun applyRealCrossDisplay(enabled: Boolean) {
841
+ isRealCrossDisplayShow = enabled
475
842
  val options = naviView.viewOptions
476
843
  options.isRealCrossDisplayShow = enabled
477
844
  naviView.viewOptions = options
@@ -491,6 +858,11 @@ class ExpoGaodeMapNaviView(context: Context, appContext: AppContext) : ExpoView(
491
858
  // 夜间模式设置 - isNightMode 属性可能不存在
492
859
  try {
493
860
  val options = naviView.viewOptions
861
+ if(enabled){
862
+ options.setMapStyle(MapStyle.NIGHT, null)
863
+ }else{
864
+ options.setMapStyle(MapStyle.DAY, null)
865
+ }
494
866
  // options.isNightMode = enabled // 该属性可能不存在
495
867
  // 可以通过其他方式设置夜间模式
496
868
  naviView.viewOptions = options
@@ -578,7 +950,12 @@ class ExpoGaodeMapNaviView(context: Context, appContext: AppContext) : ExpoView(
578
950
  Log.e("ExpoGaodeMapNaviView", "Failed to set traffic light view visibility", e)
579
951
  }
580
952
  }
581
-
953
+
954
+ fun applyIsNaviTravelView(enabled: Boolean){
955
+ isNaviTravelView = enabled
956
+ aMapNavi?.isNaviTravelView = enabled
957
+ }
958
+
582
959
  /**
583
960
  * 设置路线转向箭头的可见性
584
961
  * @param visible true-显示 false-隐藏
@@ -586,8 +963,9 @@ class ExpoGaodeMapNaviView(context: Context, appContext: AppContext) : ExpoView(
586
963
  */
587
964
  fun applyNaviArrowVisible(visible: Boolean) {
588
965
  try {
966
+ isNaviArrowVisible = visible
589
967
  val options = naviView.viewOptions
590
- options.setNaviArrowVisible(visible)
968
+ options.isNaviArrowVisible = visible
591
969
  naviView.viewOptions = options
592
970
  Log.d("ExpoGaodeMapNaviView", "Navi arrow visibility set to: $visible")
593
971
  } catch (e: Exception) {
@@ -649,4 +1027,4 @@ class ExpoGaodeMapNaviView(context: Context, appContext: AppContext) : ExpoView(
649
1027
  Log.e("ExpoGaodeMapNaviView", "Error destroying navi view", e)
650
1028
  }
651
1029
  }
652
- }
1030
+ }
@@ -72,7 +72,7 @@ class ExpoGaodeMapNaviViewModule : Module() {
72
72
  view.applyCarOverlayVisible(visible)
73
73
  }
74
74
 
75
- Prop<Boolean>("trafficLightsVisible") { view, visible ->
75
+ Prop<Boolean>("showTrafficLights") { view, visible ->
76
76
  view.applyTrafficLightsVisible(visible)
77
77
  }
78
78
 
@@ -101,7 +101,44 @@ class ExpoGaodeMapNaviViewModule : Module() {
101
101
  Prop<Boolean>("showTrafficLightView") { view, show ->
102
102
  view.applyShowTrafficLightView(show)
103
103
  }
104
-
104
+
105
+ //设置是否为骑步行视图
106
+ Prop<Boolean>("isNaviTravelView") { view, isRideStepView ->
107
+ view.applyIsNaviTravelView(isRideStepView)
108
+ }
109
+
110
+ Prop<Double?>("androidStatusBarPaddingTop") { view, topDp ->
111
+ view.applyAndroidStatusBarPaddingTop(topDp)
112
+ }
113
+
114
+ Prop<Boolean>("showCamera") { view, enabled ->
115
+ view.applyShowCamera(enabled)
116
+ }
117
+
118
+ Prop<Boolean>("showUIElements") { view, visible ->
119
+ view.applyShowUIElements(visible)
120
+ }
121
+
122
+ Prop<Boolean>("showTrafficBar") { view, enabled ->
123
+ view.applyAndroidTrafficBarEnabled(enabled)
124
+ }
125
+
126
+ Prop<Boolean>("showTrafficButton"){ view, enabled ->
127
+ view.applyShowTrafficButton(enabled)
128
+ }
129
+
130
+ Prop<Boolean>("showBrowseRouteButton") { view, enabled ->
131
+ view.applyShowBrowseRouteButton(enabled)
132
+ }
133
+
134
+ Prop<Boolean>("showVectorline"){ view, enabled ->
135
+ view.applyShowVectorline(enabled)
136
+ }
137
+
138
+ Prop<Boolean>("showGreyAfterPass") { view, enabled ->
139
+ view.applyShowGreyAfterPass(enabled)
140
+ }
141
+
105
142
  // 方法
106
143
  AsyncFunction("startNavigation") { view: ExpoGaodeMapNaviView, startLat: Double, startLng: Double, endLat: Double, endLng: Double, promise: expo.modules.kotlin.Promise ->
107
144
  view.startNavigation(startLat, startLng, endLat, endLng, promise)
@@ -112,4 +149,4 @@ class ExpoGaodeMapNaviViewModule : Module() {
112
149
  }
113
150
  }
114
151
  }
115
- }
152
+ }
@@ -1,5 +1,6 @@
1
1
  package expo.modules.gaodemap.navigation
2
2
 
3
+ import android.annotation.SuppressLint
3
4
  import android.content.Context
4
5
  import com.amap.api.navi.AMapNavi
5
6
  import com.amap.api.navi.model.AMapCarInfo
@@ -43,6 +44,7 @@ class ExpoGaodeMapNavigationModule : Module() {
43
44
  private val independentRouteManager = IndependentRouteManager()
44
45
  private var independentRouteService: IndependentRouteService? = null
45
46
 
47
+ @SuppressLint("SuspiciousIndentation")
46
48
  override fun definition() = ModuleDefinition {
47
49
  Name("ExpoGaodeMapNavigation")
48
50
 
@@ -1,9 +1,7 @@
1
1
  export * from './ExpoGaodeMap.types';
2
- export * from './types';
3
2
  export { default as ExpoGaodeMapModule, getWebKey, getSDKConfig } from './ExpoGaodeMapModule';
4
3
  export type { SDKConfig, PermissionStatus } from './ExpoGaodeMapModule';
5
4
  export { default as MapView } from './ExpoGaodeMapView';
6
- export type { MapViewRef } from './ExpoGaodeMapView';
7
5
  export { Marker, Polyline, Polygon, Circle, HeatMap, MultiPoint, Cluster, } from './components/overlays';
8
6
  export { requireModule, OptionalModules, getInstalledModules, printModuleInfo, createLazyLoader, } from './utils/ModuleLoader';
9
7
  export { default } from './ExpoGaodeMapModule';
@@ -20,7 +20,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
20
20
  exports.default = exports.createLazyLoader = exports.printModuleInfo = exports.getInstalledModules = exports.OptionalModules = exports.requireModule = exports.Cluster = exports.MultiPoint = exports.HeatMap = exports.Circle = exports.Polygon = exports.Polyline = exports.Marker = exports.MapView = exports.getSDKConfig = exports.getWebKey = exports.ExpoGaodeMapModule = void 0;
21
21
  // 导出类型定义
22
22
  __exportStar(require("./ExpoGaodeMap.types"), exports);
23
- __exportStar(require("./types"), exports);
24
23
  // 导出原生模块 - 直接使用,无需封装
25
24
  var ExpoGaodeMapModule_1 = require("./ExpoGaodeMapModule");
26
25
  Object.defineProperty(exports, "ExpoGaodeMapModule", { enumerable: true, get: function () { return __importDefault(ExpoGaodeMapModule_1).default; } });
@@ -336,5 +336,5 @@ export interface ClusterProps {
336
336
  /**
337
337
  * 聚合点点击事件
338
338
  */
339
- onPress?: (event: NativeSyntheticEvent<ClusterParams>) => void;
339
+ onClusterPress?: (event: NativeSyntheticEvent<ClusterParams>) => void;
340
340
  }
@@ -106,13 +106,6 @@ export interface NaviViewProps extends ViewProps {
106
106
  * @since 6.2.0
107
107
  */
108
108
  carOverlayVisible?: boolean;
109
- /**
110
- * 是否显示交通信号灯
111
- * @platform android
112
- * @default true
113
- * @since 7.4.0
114
- */
115
- trafficLightsVisible?: boolean;
116
109
  /**
117
110
  * 路线标记点可见性配置
118
111
  * @platform android
@@ -152,26 +145,25 @@ export interface NaviViewProps extends ViewProps {
152
145
  */
153
146
  showTrafficLightView?: boolean;
154
147
  /**
155
- * 是否显示路线
156
- * @platform ios
157
- * @default true
148
+ * 导航界面顶部与状态栏的间距(单位:dp)
149
+ * @platform android
150
+ * @default 状态栏高度(单位:dp)
158
151
  */
159
- showRoute?: boolean;
152
+ androidStatusBarPaddingTop?: number;
160
153
  /**
161
- * 是否显示转向箭头
154
+ * 是否显示路线
162
155
  * @platform ios
163
156
  * @default true
164
157
  */
165
- showTurnArrow?: boolean;
158
+ showRoute?: boolean;
166
159
  /**
167
160
  * 是否显示路况光柱
168
- * @platform ios
169
161
  * @default true
170
162
  */
171
163
  showTrafficBar?: boolean;
172
164
  /**
173
165
  * 是否显示全览按钮
174
- * @platform ios
166
+ *
175
167
  * @default true
176
168
  */
177
169
  showBrowseRouteButton?: boolean;
@@ -183,31 +175,36 @@ export interface NaviViewProps extends ViewProps {
183
175
  showMoreButton?: boolean;
184
176
  /**
185
177
  * 是否显示实时交通按钮
186
- * @platform ios
178
+ *
187
179
  * @default true
188
180
  */
189
181
  showTrafficButton?: boolean;
190
182
  /**
191
183
  * 是否显示界面元素(设为false可完全自定义界面)
192
- * @platform ios
184
+ * 提示:ios 暂时无效,android 有效
193
185
  * @default true
194
186
  */
195
187
  showUIElements?: boolean;
196
188
  /**
197
189
  * 走过的路线是否置灰
198
- * @platform ios
190
+ *
199
191
  * @default false
200
192
  */
201
193
  showGreyAfterPass?: boolean;
202
194
  /**
203
195
  * 是否显示牵引线(起点到终点的飞线)
204
- * @platform ios
196
+ *
205
197
  * @default true
206
198
  */
207
199
  showVectorline?: boolean;
200
+ /**
201
+ * 设置是否为骑步行视图
202
+ * @platform android
203
+ * @default false
204
+ */
205
+ isNaviTravelView?: boolean;
208
206
  /**
209
207
  * 是否显示红绿灯图标
210
- * @platform ios
211
208
  * @default true
212
209
  */
213
210
  showTrafficLights?: boolean;
@@ -5,6 +5,7 @@
5
5
  //
6
6
  //
7
7
 
8
+ import Foundation
8
9
  import ExpoModulesCore
9
10
  import AMapNaviKit
10
11
 
@@ -84,6 +85,11 @@ public class ExpoGaodeMapNaviView: ExpoView {
84
85
 
85
86
  // MARK: - Properties
86
87
  private var driveView: AMapNaviDriveView?
88
+ private var driveViewLoaded: Bool = false
89
+ private var pendingShowUIElements: Bool?
90
+ private var pendingShowUIElementsWorkItem: DispatchWorkItem?
91
+ private var hasStartedNavi: Bool = false
92
+ private var hasReceivedFirstNaviData: Bool = false
87
93
  private var driveManager: AMapNaviDriveManager?
88
94
 
89
95
  // Props - 通用属性
@@ -136,7 +142,7 @@ public class ExpoGaodeMapNaviView: ExpoView {
136
142
  didSet { driveView?.showTrafficButton = showTrafficButton }
137
143
  }
138
144
  var showUIElements: Bool = true {
139
- didSet { driveView?.showUIElements = showUIElements }
145
+ didSet { applyShowUIElementsToDriveViewIfReady() }
140
146
  }
141
147
  var showGreyAfterPass: Bool = false {
142
148
  didSet { driveView?.showGreyAfterPass = showGreyAfterPass }
@@ -153,6 +159,10 @@ public class ExpoGaodeMapNaviView: ExpoView {
153
159
  var lineWidth: CGFloat = 0 {
154
160
  didSet { driveView?.lineWidth = lineWidth }
155
161
  }
162
+
163
+ func applyShowUIElements(_ visible: Bool) {
164
+ showUIElements = visible
165
+ }
156
166
 
157
167
  // 坐标
158
168
  private var startCoordinate: AMapNaviPoint?
@@ -222,15 +232,68 @@ public class ExpoGaodeMapNaviView: ExpoView {
222
232
  driveView?.showBrowseRouteButton = showBrowseRouteButton
223
233
  driveView?.showMoreButton = showMoreButton
224
234
  driveView?.showTrafficButton = showTrafficButton
225
- driveView?.showUIElements = showUIElements
226
235
  driveView?.showGreyAfterPass = showGreyAfterPass
227
236
  driveView?.showVectorline = showVectorline
228
237
  driveView?.showTrafficLights = showTrafficLights
229
238
  if lineWidth > 0 {
230
239
  driveView?.lineWidth = lineWidth
231
240
  }
241
+
242
+ applyShowUIElementsToDriveViewIfReady()
232
243
  }
233
-
244
+
245
+ private func applyShowUIElementsToDriveViewIfReady() {
246
+ guard driveView != nil else {
247
+ pendingShowUIElements = showUIElements
248
+ return
249
+ }
250
+
251
+ guard driveViewLoaded else {
252
+ pendingShowUIElements = showUIElements
253
+ return
254
+ }
255
+
256
+ let value = pendingShowUIElements ?? showUIElements
257
+ pendingShowUIElements = nil
258
+
259
+ if value == false && (!hasStartedNavi || !hasReceivedFirstNaviData) {
260
+ pendingShowUIElements = false
261
+ pendingShowUIElementsWorkItem?.cancel()
262
+ let workItem = DispatchWorkItem { [weak self] in
263
+ guard let self else { return }
264
+ self.applyDriveViewShowUIElements(true, remainingAttempts: 20)
265
+ }
266
+ pendingShowUIElementsWorkItem = workItem
267
+ DispatchQueue.main.asyncAfter(deadline: .now() + 0.08, execute: workItem)
268
+ return
269
+ }
270
+
271
+ pendingShowUIElementsWorkItem?.cancel()
272
+ let workItem = DispatchWorkItem { [weak self] in
273
+ guard let self else { return }
274
+ self.applyDriveViewShowUIElements(value, remainingAttempts: 20)
275
+ }
276
+ pendingShowUIElementsWorkItem = workItem
277
+
278
+ DispatchQueue.main.asyncAfter(deadline: .now() + 0.08, execute: workItem)
279
+ }
280
+
281
+ private func applyDriveViewShowUIElements(_ value: Bool, remainingAttempts: Int) {
282
+ guard let driveView else { return }
283
+
284
+ if driveView.bounds.isEmpty {
285
+ if remainingAttempts <= 0 {
286
+ return
287
+ }
288
+ DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) { [weak self] in
289
+ self?.applyDriveViewShowUIElements(value, remainingAttempts: remainingAttempts - 1)
290
+ }
291
+ return
292
+ }
293
+
294
+ driveView.showUIElements = value
295
+ }
296
+
234
297
  // MARK: - Prop Setters
235
298
  private func applyShowCamera(_ show: Bool) {
236
299
  driveView?.showCamera = show
@@ -366,6 +429,7 @@ public class ExpoGaodeMapNaviView: ExpoView {
366
429
  extension ExpoGaodeMapNaviView: AMapNaviDriveManagerDelegate {
367
430
 
368
431
  public func driveManager(onCalculateRouteSuccess driveManager: AMapNaviDriveManager) {
432
+ hasStartedNavi = true
369
433
  onRouteCalculated([
370
434
  "success": true,
371
435
  "naviType": naviType
@@ -377,6 +441,8 @@ extension ExpoGaodeMapNaviView: AMapNaviDriveManagerDelegate {
377
441
  } else {
378
442
  driveManager.startGPSNavi()
379
443
  }
444
+
445
+ applyShowUIElementsToDriveViewIfReady()
380
446
  }
381
447
 
382
448
  public func driveManager(_ driveManager: AMapNaviDriveManager, onCalculateRouteFailure error: Error) {
@@ -387,10 +453,13 @@ extension ExpoGaodeMapNaviView: AMapNaviDriveManagerDelegate {
387
453
  }
388
454
 
389
455
  public func driveManager(_ driveManager: AMapNaviDriveManager, didStartNavi naviMode: AMapNaviMode) {
456
+ hasStartedNavi = true
390
457
  onNavigationStarted([
391
458
  "type": naviMode == .emulator ? 1 : 0,
392
459
  "isEmulator": naviMode == .emulator
393
460
  ])
461
+
462
+ applyShowUIElementsToDriveViewIfReady()
394
463
  }
395
464
 
396
465
  public func driveManagerNavi(_ driveManager: AMapNaviDriveManager, didArrive wayPoint: AMapNaviPoint) {
@@ -404,6 +473,10 @@ extension ExpoGaodeMapNaviView: AMapNaviDriveManagerDelegate {
404
473
  }
405
474
 
406
475
  public func driveManager(_ driveManager: AMapNaviDriveManager, didUpdate naviLocation: AMapNaviLocation) {
476
+ if !hasReceivedFirstNaviData {
477
+ hasReceivedFirstNaviData = true
478
+ applyShowUIElementsToDriveViewIfReady()
479
+ }
407
480
  onLocationUpdate([
408
481
  "latitude": naviLocation.coordinate.latitude,
409
482
  "longitude": naviLocation.coordinate.longitude,
@@ -413,6 +486,10 @@ extension ExpoGaodeMapNaviView: AMapNaviDriveManagerDelegate {
413
486
  }
414
487
 
415
488
  public func driveManager(_ driveManager: AMapNaviDriveManager, didUpdate naviInfo: AMapNaviInfo) {
489
+ if !hasReceivedFirstNaviData {
490
+ hasReceivedFirstNaviData = true
491
+ applyShowUIElementsToDriveViewIfReady()
492
+ }
416
493
  onNavigationInfoUpdate([
417
494
  "currentRoadName": naviInfo.currentRoadName ?? "",
418
495
  "nextRoadName": naviInfo.nextRoadName ?? "",
@@ -458,6 +535,13 @@ extension ExpoGaodeMapNaviView: AMapNaviDriveManagerDelegate {
458
535
  extension ExpoGaodeMapNaviView: AMapNaviDriveViewDelegate {
459
536
 
460
537
  public func driveViewDidLoad(_ driveView: AMapNaviDriveView) {
538
+ driveViewLoaded = true
539
+ applyViewOptions()
540
+ applyShowUIElementsToDriveViewIfReady()
461
541
  onNavigationReady([:])
462
542
  }
543
+
544
+ public func driveViewEdgePadding(_ driveView: AMapNaviDriveView) -> UIEdgeInsets {
545
+ return .zero
546
+ }
463
547
  }
@@ -76,7 +76,7 @@ public class ExpoGaodeMapNaviViewModule: Module {
76
76
  view.showRoute = value
77
77
  }
78
78
 
79
- Prop("showTurnArrow") { (view: ExpoGaodeMapNaviView, value: Bool) in
79
+ Prop("naviArrowVisible") { (view: ExpoGaodeMapNaviView, value: Bool) in
80
80
  view.showTurnArrow = value
81
81
  }
82
82
 
@@ -97,7 +97,7 @@ public class ExpoGaodeMapNaviViewModule: Module {
97
97
  }
98
98
 
99
99
  Prop("showUIElements") { (view: ExpoGaodeMapNaviView, value: Bool) in
100
- view.showUIElements = value
100
+ view.applyShowUIElements(value)
101
101
  }
102
102
 
103
103
  Prop("showGreyAfterPass") { (view: ExpoGaodeMapNaviView, value: Bool) in
package/package.json CHANGED
@@ -1,17 +1,11 @@
1
1
  {
2
2
  "name": "expo-gaode-map-navigation",
3
- "version": "1.1.4",
3
+ "version": "1.1.5-next.0",
4
4
  "description": "高德地图导航功能模块 - 路径规划、导航引导,独立版本包含完整地图功能",
5
+ "author": "<TomWq> (https://github.com/TomWq)",
6
+ "repository": "https://github.com/TomWq/expo-gaode-map",
5
7
  "main": "build/index.js",
6
8
  "types": "build/index.d.ts",
7
- "files": [
8
- "build",
9
- "android",
10
- "ios",
11
- "app.plugin.js",
12
- "expo-module.config.json",
13
- "plugin/build"
14
- ],
15
9
  "scripts": {
16
10
  "build": "expo-module build && bun run build:plugin",
17
11
  "build:plugin": "tsc --project plugin/tsconfig.json",
@@ -22,6 +16,31 @@
22
16
  "prepublishOnly": "expo-module prepublishOnly",
23
17
  "expo-module": "expo-module"
24
18
  },
19
+ "devDependencies": {
20
+ "@expo/config-plugins": "~54.0.4",
21
+ "@types/react": "~19.1.0",
22
+ "expo": "^54.0.31",
23
+ "expo-module-scripts": "^5.0.8",
24
+ "react-native": "0.81.5",
25
+ "typescript": "^5.9.3"
26
+ },
27
+ "peerDependencies": {
28
+ "expo": "*",
29
+ "react": "*",
30
+ "react-native": "*"
31
+ },
32
+ "bugs": {
33
+ "url": "https://github.com/TomWq/expo-gaode-map/issues"
34
+ },
35
+ "files": [
36
+ "build",
37
+ "android",
38
+ "ios",
39
+ "app.plugin.js",
40
+ "expo-module.config.json",
41
+ "plugin/build"
42
+ ],
43
+ "homepage": "https://github.com/TomWq/expo-gaode-map#readme",
25
44
  "keywords": [
26
45
  "react-native",
27
46
  "expo",
@@ -32,27 +51,5 @@
32
51
  "高德地图",
33
52
  "导航"
34
53
  ],
35
- "repository": "https://github.com/TomWq/expo-gaode-map",
36
- "bugs": {
37
- "url": "https://github.com/TomWq/expo-gaode-map/issues"
38
- },
39
- "author": "<TomWq> (https://github.com/TomWq)",
40
- "license": "MIT",
41
- "homepage": "https://github.com/TomWq/expo-gaode-map#readme",
42
- "dependencies": {
43
- "supercluster": "^8.0.1"
44
- },
45
- "devDependencies": {
46
- "@expo/config-plugins": "^9.1.7",
47
- "@types/react": "~19.1.0",
48
- "expo": "^54.0.18",
49
- "expo-module-scripts": "^5.0.7",
50
- "react-native": "0.81.5",
51
- "typescript": "^5.9.3"
52
- },
53
- "peerDependencies": {
54
- "expo": "*",
55
- "react": "*",
56
- "react-native": "*"
57
- }
54
+ "license": "MIT"
58
55
  }