kotlin 如何在jetpack compose中滚动/缩放垂直滚动的Map?

ca1c2owp  于 2023-05-18  发布在  Kotlin
关注(0)|答案(2)|浏览(237)

我正在实现一个元素列表,并在一列中显示垂直滚动条。每个元素都包含一个map。问题是,在这些Map上我不能用手指手势缩放,也不能在这些Map上垂直滚动。我可以水平移动,但移动不是流畅的。就好像列的垂直滚动影响了与Map的交互。下面是代码,如果有人可以帮助我:
主要:

LazyColumn(
    modifier = Modifier
        .fillMaxSize()
        .padding(vertical = 8.dp)
) {
    items(state.data.elements) { element ->
        ElementMap(
            lat = element.lat,
            lon = element.lon
        )
    }
}

元素Map:

import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.MapView

fun ElementMap(
    lat: Double,
    lon: Double
) {

    val mapView = rememberMapViewWithLifeCycle()

    Column(
        modifier = Modifier
            .background(Color.White)
    ) {
        AndroidView(
            {
                mapView
            }
        ) {
            mapView.getMapAsync {
                val map = it
                map.uiSettings.isZoomControlsEnabled = false
                map.addMarker(marker(lat, lon, 16f, 250f))
                map.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(lat, lon), 16f))
                map.mapType = GoogleMap.MAP_TYPE_HYBRID
            }
        }
    }
}

@Composable
fun rememberMapViewWithLifeCycle(): MapView {
    val context = LocalContext.current
    val mapView = remember {
        MapView(context).apply {
            id = R.id.map_frame
        }
    }
    val lifeCycleObserver = rememberMapLifecycleObserver(mapView)
    val lifeCycle = LocalLifecycleOwner.current.lifecycle
    DisposableEffect(lifeCycle) {
        lifeCycle.addObserver(lifeCycleObserver)
        onDispose {
            lifeCycle.removeObserver(lifeCycleObserver)
        }
    }

    return mapView
}

@Composable
fun rememberMapLifecycleObserver(mapView: MapView): LifecycleEventObserver =
    remember(mapView) {
        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()
            }
        }
    }

我曾经尝试过全屏显示Map,也就是在垂直滚动之外,这样手势就能正常工作,我可以缩放以及向各个方向滚动。因此,这似乎是一个问题,有一个Map在一个卷轴,但我不知道如何解决这个问题。

px9o7tmv

px9o7tmv1#

这种变通方法工作得很好。参考https://github.com/googlemaps/android-maps-compose/blob/main/app/src/main/java/com/google/maps/android/compose/MapInColumnActivity.kt

class MapInColumnActivity : ComponentActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
        // Observing and controlling the camera's state can be done with a CameraPositionState
        val cameraPositionState = rememberCameraPositionState {
            position = defaultCameraPosition
        }
        var columnScrollingEnabled by remember { mutableStateOf(true) }

        // Use a LaunchedEffect keyed on the camera moving state to enable column scrolling when the camera stops moving
        LaunchedEffect(cameraPositionState.isMoving) {
            if (!cameraPositionState.isMoving) {
                columnScrollingEnabled = true
                Log.d(TAG, "Map camera stopped moving - Enabling column scrolling...")
            }
        }

        MapInColumn(
            modifier = Modifier.fillMaxSize(),
            cameraPositionState,
            columnScrollingEnabled = columnScrollingEnabled,
            onMapTouched = {
                columnScrollingEnabled = false
                Log.d(
                    TAG,
                    "User touched map - Disabling column scrolling after user touched this Box..."
                )
            },
            onMapLoaded = { }
        )
    }
}

}

@Composable

fun MapInColumn(
    modifier: Modifier = Modifier,
    cameraPositionState: CameraPositionState,
    columnScrollingEnabled: Boolean,
    onMapTouched: () -> Unit,
    onMapLoaded: () -> Unit,
) {
    Surface(
        modifier = modifier,
        color = MaterialTheme.colors.background
    ) {
        var isMapLoaded by remember { mutableStateOf(false) }

        Column(
            Modifier
                .fillMaxSize()
                .verticalScroll(
                    rememberScrollState(),
                    columnScrollingEnabled
                ),
            horizontalAlignment = Alignment.Start
        ) {
            Spacer(modifier = Modifier.padding(10.dp))
            for (i in 1..20) {
                Text(
                    text = "Item $i",
                    modifier = Modifier
                        .padding(start = 10.dp)
                        .testTag("Item $i")
                )
            }
            Spacer(modifier = Modifier.padding(10.dp))

            Box(
                Modifier
                    .fillMaxWidth()
                    .height(200.dp)
            ) {
                GoogleMapViewInColumn(
                    modifier = Modifier
                        .fillMaxSize()
                        .testTag("Map")
                        .pointerInteropFilter(
                            onTouchEvent = {
                                when (it.action) {
                                    MotionEvent.ACTION_DOWN -> {
                                        onMapTouched()
                                        false
                                    }
                                    else -> {
                                        Log.d(
                                            TAG,
                                            "MotionEvent ${it.action} - this never triggers."
                                        )
                                        true
                                    }
                                }
                            }
                        ),
                    cameraPositionState = cameraPositionState,
                    onMapLoaded = {
                        isMapLoaded = true
                        onMapLoaded()
                    },
                )
                if (!isMapLoaded) {
                    androidx.compose.animation.AnimatedVisibility(
                        modifier = Modifier
                            .fillMaxSize(),
                        visible = !isMapLoaded,
                        enter = EnterTransition.None,
                        exit = fadeOut()
                    ) {
                        CircularProgressIndicator(
                            modifier = Modifier
                                .background(MaterialTheme.colors.background)
                                .wrapContentSize()
                        )
                    }
                }
            }
            Spacer(modifier = Modifier.padding(10.dp))
            for (i in 21..40) {
                Text(
                    text = "Item $i",
                    modifier = Modifier
                        .padding(start = 10.dp)
                        .testTag("Item $i")
                )
            }
            Spacer(modifier = Modifier.padding(10.dp))
        }
    }
}

    @Composable

private fun GoogleMapViewInColumn(
    modifier: Modifier,
    cameraPositionState: CameraPositionState,
    onMapLoaded: () -> Unit,
) {
    val singaporeState = rememberMarkerState(position = singapore)

    var uiSettings by remember { mutableStateOf(MapUiSettings(compassEnabled = false)) }
    var mapProperties by remember {
        mutableStateOf(MapProperties(mapType = MapType.NORMAL))
    }

    GoogleMap(
        modifier = modifier,
        cameraPositionState = cameraPositionState,
        properties = mapProperties,
        uiSettings = uiSettings,
        onMapLoaded = onMapLoaded
    ) {
        // Drawing on the map is accomplished with a child-based API
        val markerClick: (Marker) -> Boolean = {
            Log.d(TAG, "${it.title} was clicked")
            cameraPositionState.projection?.let { projection ->
                Log.d(TAG, "The current projection is: $projection")
            }
            false
        }
        MarkerInfoWindowContent(
            state = singaporeState,
            title = "Singapore",
            onClick = markerClick,
            draggable = true,
        ) {
            Text(it.title ?: "Title", color = Color.Red)
        }
    }
}
vbkedwbf

vbkedwbf2#

我已经设法防止Map由于滚动而丢失触摸事件。我已经创建了一个我自己的类实现MapView(在com.google.android.gms.maps包中),如this answer所述。

class CustomMapView(context: Context) : MapView(context) {

    override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
        when (ev.action) {
            MotionEvent.ACTION_UP   -> parent.requestDisallowInterceptTouchEvent(false)
            MotionEvent.ACTION_DOWN -> parent.requestDisallowInterceptTouchEvent(true)
        }
        return super.dispatchTouchEvent(ev)
    }
}

所以我没有使用MapView,而是使用了我的CustomMapView类,它工作得很好。

相关问题