Jetpack 中的地图组成

Posted

技术标签:

【中文标题】Jetpack 中的地图组成【英文标题】:Maps in Jetpack compose 【发布时间】:2021-12-01 00:30:32 【问题描述】:

我正在尝试获取一个简单的地图作为我的 mainActivity 来测试使用 compose 的地图是如何工作的。不幸的是,我一开始就失败了一个错误消息,它基本上只说“IllegalStateException”。 我尝试从此处的原始 Google 示例中提取地图代码: https://github.com/android/compose-samples/tree/main/Crane 我尝试重建一个简单的 Composable,在 Google Cloud Platform 上创建了一个 API 密钥并将其添加到我的清单中。

那是MainActivity

package com.veloce.mapstesting

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.annotation.FloatRange
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import com.google.android.libraries.maps.CameraUpdateFactory
import com.google.android.libraries.maps.GoogleMap
import com.google.android.libraries.maps.MapView
import com.google.android.libraries.maps.model.LatLng
import com.google.maps.android.ktx.addMarker
import com.google.maps.android.ktx.awaitMap
import kotlinx.coroutines.launch

class MainActivity : ComponentActivity() 
    override fun onCreate(savedInstanceState: Bundle?) 
        super.onCreate(savedInstanceState)

        setContent 
            val mapView = rememberMapViewWithLifecycle()
            MapViewContainer(mapView)
        
    


const val InitialZoom = 5f
const val MinZoom = 2f
const val MaxZoom = 20f

@Composable
fun MapViewContainer(map: MapView) 
    val cameraPosition = remember 
        LatLng(48.2050491798, 16.3701485194)
    

    LaunchedEffect(map) 
        val googleMap = map.awaitMap()
        googleMap.addMarker  position(cameraPosition) 
        googleMap.moveCamera(CameraUpdateFactory.newLatLng(cameraPosition))
    

    var zoom by rememberSaveable(map)  mutableStateOf(InitialZoom) 
    ZoomControls(zoom) 
        zoom = it.coerceIn(MinZoom, MaxZoom)
    

    val coroutineScope = rememberCoroutineScope()
    AndroidView( map )  mapView ->
        val mapZoom = zoom
        coroutineScope.launch 
            val googleMap = mapView.awaitMap()
            googleMap.setZoom(mapZoom)
            googleMap.moveCamera(CameraUpdateFactory.newLatLng(cameraPosition))
        
    


@Composable
private fun ZoomControls(
    zoom: Float,
    onZoomChanged: (Float) -> Unit
) 
    Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) 
        ZoomButton("-", onClick =  onZoomChanged(zoom * 0.8f) )
        ZoomButton("+", onClick =  onZoomChanged(zoom * 1.2f) )
    


@Composable
fun ZoomButton(text: String, onClick: () -> Unit) 
    Button(
        modifier = Modifier.padding(8.dp),
        colors = ButtonDefaults.buttonColors(
            backgroundColor = MaterialTheme.colors.onPrimary,
            contentColor = MaterialTheme.colors.primary
        ),
        onClick = onClick
    ) 
        Text(text = text, style = MaterialTheme.typography.h5)
    


fun GoogleMap.setZoom(
    @FloatRange(from = MinZoom.toDouble(), to = MaxZoom.toDouble()) zoom: Float
) 
    resetMinMaxZoomPreference()
    setMinZoomPreference(zoom)
    setMaxZoomPreference(zoom)

这些是MapUtils

package com.veloce.mapstesting

import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import com.google.android.libraries.maps.MapView
import java.lang.IllegalStateException

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

    val lifecycleObserver = rememberMapLifecycleObserver(mapView)
    val lifecycle = LocalLifecycleOwner.current.lifecycle
    DisposableEffect(lifecycle) 
        lifecycle.addObserver(lifecycleObserver)
        onDispose  lifecycle.removeObserver(lifecycleObserver) 
    
    return mapView



private fun rememberMapLifecycleObserver(mapView: MapView): LifecycleEventObserver =
    LifecycleEventObserver  _, event ->
        when (event) 
            Lifecycle.Event.ON_CREATE -> 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()
        
    

我错过了什么吗?

【问题讨论】:

“我刚开始就失败了一个错误消息,它基本上只说“IllegalStateException”“——在你的问题中包含堆栈跟踪仍然是个好主意。虽然详细信息可能无法直接帮助您,但它们可能会帮助那些希望尝试帮助您解决问题的人。 FWIW,piotrprus.medium.com/… 可能会给你一些想法。 考虑为这个错误跟踪器问题添加您的投票,以方便 Google 地图与 Compose 一起使用:issuetracker.google.com/issues/198126189 对您的可组合的 IMPL 很有趣……我以前从未见过具有返回类型的函数实例。我必须自己尝试一下。 【参考方案1】:

我不知道你是否正在阅读这篇文章,但你忘记了在生命周期中包含 ON_START 事件,所以你抛出了异常。你也在 ON_CREATE 上调用 onStart。

还可以考虑将生命周期观察者填充到 DisposableEffect 的范围内,并使 DisposableEffect 也知道 mapView(将其作为参数提供)。

【讨论】:

【参考方案2】:

Jetpack Compose 的官方谷歌地图库最近发布了,看看吧:

Google Maps Compose

【讨论】:

以上是关于Jetpack 中的地图组成的主要内容,如果未能解决你的问题,请参考以下文章

相对于jetpack中的其他元素创建垂直链组成ConstraintLayout?

JetpackJetpack 简介 ( 官方架构设计标准 | Jetpack 组成套件 | Jetpack架构 | Jetpack 的存在意义 | AndroidX 与 Jetpack 的关系 )

Android Jetpack compose:使用谷歌地图在地图创建时崩溃

Jetpack 组成没有片段的导航架构?

Jetpack 在 LazyCloumn 中组成 LazyColumn

如何在jetpack compose中的网格项目之间添加空格