Android中Yandex MapKit搭配MapView时Snackbar不可见问题排查
首先,这个问题大概率是Yandex MapKit的MapView采用SurfaceView/TextureView导致的层级覆盖问题。在Android 9的小米Mi9设备上,SurfaceView的绘制层级默认高于普通View(比如Snackbar的视图),所以Snackbar虽然已经创建并存在于视图树中,但被MapView遮挡住了——这也解释了为什么切换应用/打开搜索框后会显示(这些操作触发了视图层级的重新计算或重绘),且点击按钮能生效(视图实际存在只是看不见)。而模拟器的渲染逻辑和真实定制设备有差异,所以没有出现这个问题。
下面是几个不需要裁剪地图的解决方案:
方案1:改用CoordinatorLayout作为根布局
Snackbar和CoordinatorLayout的兼容性最好,CoordinatorLayout能自动处理子视图的层级和位置,确保Snackbar显示在最上层。修改你的布局文件:
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/placesMapLayout" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".activities.PlacesMapActivity"> <com.yandex.mapkit.mapview.MapView android:id="@+id/placesMapView" android:layout_width="match_parent" android:layout_height="match_parent"/> <com.google.android.material.textfield.TextInputLayout android:id="@+id/outlinedTextField" android:layout_width="match_parent" android:layout_height="wrap_content" app:boxBackgroundColor="@color/white" style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox" android:layout_margin="20dp" android:hint="@null"> <com.google.android.material.textfield.TextInputEditText android:id="@+id/searchEdit" android:imeOptions="actionSearch" android:inputType="text" app:boxBackgroundColor="@color/white" android:layout_width="match_parent" android:layout_height="wrap_content"/> </com.google.android.material.textfield.TextInputLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout>
然后保持原来的Snackbar创建代码不变即可,CoordinatorLayout会自动把Snackbar放在正确的层级。
方案2:降低MapView的Z轴层级
如果不想修改根布局,可以通过调整MapView的translateZ属性,让它的层级低于普通View:
在布局文件的MapView标签中添加:
android:translateZ="-1dp"
这个属性会降低MapView的绘制优先级,让Snackbar这类普通View能显示在它上面。注意这个属性仅在Android 5.0(API 21)及以上生效,你的小米Mi9是Android9,完全适用。
方案3:手动将Snackbar视图添加到根布局
如果上面两种方法都不适用,可以绕过Snackbar.make()的默认容器,手动把Snackbar的视图添加到根布局的最上层:
val snackbar = Snackbar.make(placesMapLayout, foundObject.name.toString(), Snackbar.LENGTH_INDEFINITE) // 获取Snackbar的视图 val snackbarView = snackbar.view // 获取根布局 val rootLayout = findViewById<RelativeLayout>(R.id.placesMapLayout) // 设置布局参数,让Snackbar固定在底部 val params = RelativeLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT ).apply { addRule(RelativeLayout.ALIGN_PARENT_BOTTOM) // 可以添加margin避免被系统导航栏遮挡 bottomMargin = resources.getDimensionPixelSize(R.dimen.snackbar_bottom_margin) } // 添加到根布局的最上层 rootLayout.addView(snackbarView, params) // 显示Snackbar snackbar.show()
这样能强制让Snackbar的视图处于根布局的最上层,不会被MapView遮挡。
内容的提问来源于stack exchange,提问作者makeitokay

