在 Jetpack Compose 中保持 Google 地图状态

AuS*_*ike 8 android google-maps android-jetpack android-jetpack-compose

我正在尝试构建一个可导航到多个不同屏幕的应用程序(使用底部导航)。其中一个屏幕,startDestination,是 Google 地图视图,查看官方撰写示例:Crane使其工作,并且确实如此。

然而,当导航到另一个屏幕并返回时,画面MapView会重新构图并缓慢加载回来。我们从初始相机位置、缩放级别等开始。可能有一种方法可以remember重新应用这些属性,但我更感兴趣的是保持 Google 地图视图的完整状态不变。(看看当前的 Android 版 Google 地图应用程序,它完全符合我的要求,尽管它们没有使用 Jetpack Compose)

有办法实现这一点吗?

remember已经MapView

@Composable
fun rememberMapViewWithLifecycle(): MapView {
    val context = LocalContext.current
    val mapView = remember {
        MapView(context).apply {
            id = R.id.map
        }
    }

    val lifecycle = LocalLifecycleOwner.current.lifecycle
    DisposableEffect(lifecycle, mapView) {
        // Make MapView follow the current lifecycle
        val lifecycleObserver = getMapLifecycleObserver(mapView)
        lifecycle.addObserver(lifecycleObserver)
        onDispose {
            lifecycle.removeObserver(lifecycleObserver)
        }
    }

    return mapView
}

private fun getMapLifecycleObserver(mapView: MapView): LifecycleEventObserver =
    LifecycleEventObserver { _, event ->
        when (event) {
            Lifecycle.Event.ON_CREATE -> mapView.onCreate(Bundle())
            Lifecycle.Event.ON_START -> mapView.onStart()
            Lifecycle.Event.ON_RESUME -> mapView.onResume()
            Lifecycle.Event.ON_PAUSE -> mapView.onPause()
            Lifecycle.Event.ON_STOP -> mapView.onStop()
            Lifecycle.Event.ON_DESTROY -> mapView.onDestroy()
            else -> throw IllegalStateException()
        }
    }
Run Code Online (Sandbox Code Playgroud)

为了提供更多上下文,MapView位于此屏幕的顶部

@ExperimentalMaterialApi
@Composable
fun MapsScreen(
    modifier: Modifier = Modifier,
    viewModel: EventViewModel = viewModel()
) {
    ...
    val mapView = rememberMapViewWithLifecycle()
    MapsScreenView(modifier, uiState, mapView)
}
Run Code Online (Sandbox Code Playgroud)

我尝试过的一种完全不同的方法是通过 a BackdropScaffolda中Scaffold,因为我想要BottomBar..) 其中backLayerContentMapsScreen()frontLayerContent其他屏幕,配置“前面”,以便在活动时它将覆盖整个屏幕。感觉真的很丑陋和可怕,但它有点管用..

Scaffold(
    topBar = {
        SmallTopAppBar(
            title = { Text(text = "Test") },
        )
    },
    bottomBar = {
        BottomBar(navController) { screen ->
            showMaps = screen == Screen.MainMaps
            coroutineScope.launch {
                if (showMaps) scaffoldState.reveal() else scaffoldState.conceal()
            }
        }
    },
    content = { innerPadding ->
        Box(modifier = Modifier.padding(innerPadding)) {
            BackdropScaffold(
                scaffoldState = scaffoldState,
                appBar = { },
                frontLayerContent = {
                    EventsScreen()
                },
                backLayerContent = {
                    MapsScreen()
                },
                peekHeight = if (showMaps) 300.dp else 0.dp,
                headerHeight = if (showMaps) BackdropScaffoldDefaults.HeaderHeight else 0.dp,
                gesturesEnabled = showMaps
            )
        }
    }
)
Run Code Online (Sandbox Code Playgroud)

有人遇到同样的问题并找到实际的解决方案吗?(我猜我们确实需要 Jetpack Compose 支持,而不是这种方法AndroidView

Nei*_*ige 3

Google 刚刚发布了一个库来处理 MapView 状态Android-Maps-Compose

val cameraPositionState: CameraPositionState = rememberCameraPositionState()
GoogleMap(cameraPositionState = cameraPositionState)
Button(onClick = { cameraPositionState.move(CameraUpdateFactory.zoomIn()) }) { 
 Text(text = "Zoom In") 
}
Run Code Online (Sandbox Code Playgroud)