Maksymilian Tomczyk
Maksymilian Tomczyk

Reputation: 1341

Column with .scrollable() modifier breaks map vertical scroll

The problem

I'm trying to implement simple map view inside scrollable column. The problem is that I can't scroll map vertically, as scroll event is captured by column and instead of map, whole column is scrolling. Is there any way to disable column scrolling on map element? I thought about using .nestedScroll() modifier, but I can't find a way to make it work as desired.

Code

LocationInput (child)

// Not important in context of question, but I left it so the code is complete
@Composable
private 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()
      }
    }
  }

// Not important in context of question, but I left it so the code is complete
@Composable
private fun rememberMapViewWithLifecycle(): MapView {
  val context = LocalContext.current
  val mapView = remember {
    MapView(context)
  }

  // Makes MapView follow the lifecycle of this composable
  val lifecycleObserver = rememberMapLifecycleObserver(mapView)
  val lifecycle = LocalLifecycleOwner.current.lifecycle
  DisposableEffect(lifecycle) {
    lifecycle.addObserver(lifecycleObserver)
    onDispose {
      lifecycle.removeObserver(lifecycleObserver)
    }
  }

  return mapView
}


@Composable
fun LocationInput() {
  val map = rememberMapViewWithLifecycle()
  Column(Modifier.fillMaxSize()) {
    var mapInitialized by remember(map) { mutableStateOf(false) }
    val googleMap = remember { mutableStateOf<GoogleMap?>(null) }

    LaunchedEffect(map, mapInitialized) {
      if (!mapInitialized) {
        googleMap.value = map.awaitMap()
        googleMap.value!!.uiSettings.isZoomGesturesEnabled = true
        mapInitialized = true
      }
    }

    AndroidView({ map }, Modifier.clip(RoundedCornerShape(6.dp))) { mapView ->

    }
  }
}

ScrollableColumn (parent)

@Composable
fun TallView() {
  Column(Modifier.verticalScroll(rememberScrollState())) {
    Spacer(Modifier.height(15.dp))
    Text(text = "Content", style = MaterialTheme.typography.h3)
    Text(text = "Content", style = MaterialTheme.typography.h3)
    Text(text = "Content", style = MaterialTheme.typography.h3)
    Text(text = "Content", style = MaterialTheme.typography.h3)
    Text(text = "Content", style = MaterialTheme.typography.h3)
    Row(Modifier.height(250.dp)) {
      LocationInput()
    }
    Text(text = "Content", style = MaterialTheme.typography.h3)
    Text(text = "Content", style = MaterialTheme.typography.h3)
    Text(text = "Content", style = MaterialTheme.typography.h3)
    Text(text = "Content", style = MaterialTheme.typography.h3)
    Text(text = "Content", style = MaterialTheme.typography.h3)
  }
}

Screen Capture

enter image description here

Upvotes: 4

Views: 2793

Answers (1)

Maksymilian Tomczyk
Maksymilian Tomczyk

Reputation: 1341

Okay, so after I posted a question I tried to fix a problem again, and I found a working solution. However I'm not sure if it's the best way to achieve desired effect.

I'm manually handling drag event on AndroidView used to present map.

Code

// AndroidView in LocationInput file:

    AndroidView({ map },
      Modifier
        .clip(RoundedCornerShape(6.dp))
        .pointerInput(Unit) {
          detectDragGestures { change, dragAmount ->
            change.consumeAllChanges()
            googleMap.value!!.moveCamera(
              CameraUpdateFactory.scrollBy(
                dragAmount.x * -1,
                dragAmount.y * -1
              )
            )
          }
        })
    { mapView ->

    }

Upvotes: 2

Related Questions