android-maps-compose
android-maps-compose copied to clipboard
When used in a LazyColumn, GoogleMap cannot be scrolled vertically
Thanks for your work on this one, it's really great to finally have an official Compose wrapper for Google Maps!
In our use case, we have a custom GoogleMaps wrapper using AndroidView that sits inside a LazyColumn. It is able to be scrolled vertically and horizontally without scrolling the LazyColumn by using a transparent view and calling .requestDisallowInterceptTouchEvent(true)
on the parent.
We are hoping to switch to this, but we noticed it still suffers from the original issue we had to work around. Is usage in a LazyColumn a supported use case and is there a more Compose-friendly way to get nested scrolling working properly with this wrapper?
Thanks!
Steps to reproduce
- Include GoogleMap in a LazyColumn
- Vertically drag on the map to attempt to scroll it
- Observe the LazyColumn scrolls instead of the map
Thanks!
@JRR-OSU Thank you for opening this issue. 🙏 Please check out these other resources that might be applicable:
- Support Console - If you have a support contract.
- Discord - chat with other developers
-
StackOverflow - use the
google-maps
tag - Google Maps Platform issue trackers
This is an automated message, feel free to ignore.
I have not yet been able to test this scenario. Perhaps a boolean property should be exposed in the GoogleMap
composable to support the case when the map is nested in a scrollable parent as implementing the default GoogleMap
using the solution you had mentioned may have unintended consequences in other use cases. Feel free to chime in with other ideas as well.
I successfully solved it with cameraPositionState: Column ( .verticalScroll(rememberScrollState(), enabled = !cameraPositionState.isMoving) )
Thanks @sandorbogyo. Just confirmed that that solution works.
I think it'd be nice to have that solution in the documentation, what do you think?
@LouisCAD good idea. Would be good to have under a "Common Patterns" section. I'd be happy to add but feel free to send a pull request as well.
If you have the time, it's best that you do it, I'm quite busy working with OSS projects and starting a company.
This solution does not work as mentioned here link
Please re open this issue and make sure to test it for yourself before accepting a solution
I'd like to request for this issue to be reopened, as it has not been adequately addressed. There is a documented workaround available now thanks to @barbeau, but that's all it is, a workaround, and it's fairly messy. It's also unclear what parts of the elaborate sample code are needed to actually make it work and what can be left out. (I figured it out via my own minimal sample project.)
A Compose component that is draggable by nature should expose draggable behavior out of the box even in the context of nested scrolling, without additional configuration needed.
A custom wrapper using requestDisallowInterceptTouchEvent()
as described in the OP may be a good approach, and as @arriolac suggested it can be controlled by a flag for the time being to gather feedback. This is the approach that I've used for years, but maps-compose has taken it away for now.
Another, preferable, avenue that should be fully explored is the standard Compose nested scrolling support that has been worked on here: https://issuetracker.google.com/issues/174348612. The work is ongoing and I have pointed out its current inapplicability to MapView, so this would be the time to connect with the people behind it and see if it can be done.
Sorry for the very late reply here, I've finally had some time to circle back to this library.
In #78 a solution was added to allow for scrolling working inside a normal Column. The solution doesn't work for LazyColumn, but I've found it can easily be adapted to work. Just swap out the MapInColumn with the code below in the test app to see it in action. Seems to work well!
If others can verify this works for them, I'd like to see the docs just updated to show something like this as an example, and then we can again close this issue. Thanks all!
@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun MapInLazyColumn(modifier: Modifier = Modifier,
cameraPositionState: CameraPositionState,
columnScrollingEnabled: Boolean,
onMapTouched: () -> Unit,
onMapLoaded: () -> Unit,) {
var isMapLoaded by remember { mutableStateOf(false) }
LazyColumn(modifier, userScrollEnabled = columnScrollingEnabled) {
item {
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) {
AnimatedVisibility(
modifier = Modifier
.fillMaxSize(),
visible = !isMapLoaded,
enter = EnterTransition.None,
exit = fadeOut()
) {
CircularProgressIndicator(
modifier = Modifier
.background(MaterialTheme.colors.background)
.wrapContentSize()
)
}
}
}
}
items(100) { item ->
Text("$item", modifier = Modifier
.padding(start = 10.dp, bottom = 10.dp)
.testTag("Item $item"))
}
}
}
Sorry for the very late reply here, I've finally had some time to circle back to this library.
In #78 a solution was added to allow for scrolling working inside a normal Column. The solution doesn't work for LazyColumn, but I've found it can easily be adapted to work. Just swap out the MapInColumn with the code below in the test app to see it in action. Seems to work well!
If others can verify this works for them, I'd like to see the docs just updated to show something like this as an example, and then we can again close this issue. Thanks all!
@OptIn(ExperimentalComposeUiApi::class) @Composable fun MapInLazyColumn(modifier: Modifier = Modifier, cameraPositionState: CameraPositionState, columnScrollingEnabled: Boolean, onMapTouched: () -> Unit, onMapLoaded: () -> Unit,) { var isMapLoaded by remember { mutableStateOf(false) } LazyColumn(modifier, userScrollEnabled = columnScrollingEnabled) { item { 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) { AnimatedVisibility( modifier = Modifier .fillMaxSize(), visible = !isMapLoaded, enter = EnterTransition.None, exit = fadeOut() ) { CircularProgressIndicator( modifier = Modifier .background(MaterialTheme.colors.background) .wrapContentSize() ) } } } } items(100) { item -> Text("$item", modifier = Modifier .padding(start = 10.dp, bottom = 10.dp) .testTag("Item $item")) } } }
I wasn't able to get it working exactly like this, but the experimental motionEventSpy worked like a charm:
var columnScrollingEnabled: Boolean by remember { mutableStateOf(true) }
...
LazyColumn(userScrollEnabled = columnScrollingEnabled)
...
item {
GoogleMap(Modifier.motionEventSpy {
when (it.action) {
MotionEvent.ACTION_DOWN -> {
columnScrollingEnabled = false
}
MotionEvent.ACTION_UP -> {
columnScrollingEnabled = true
}
}
},
...
I successfully solved it with cameraPositionState: Column ( .verticalScroll(rememberScrollState(), enabled = !cameraPositionState.isMoving) )
Didn't work for me
I wasn't able to get it working exactly like this, but the experimental motionEventSpy worked like a charm:
var columnScrollingEnabled: Boolean by remember { mutableStateOf(true) } ... LazyColumn(userScrollEnabled = columnScrollingEnabled) ... item { GoogleMap(Modifier.motionEventSpy { when (it.action) { MotionEvent.ACTION_DOWN -> { columnScrollingEnabled = false } MotionEvent.ACTION_UP -> { columnScrollingEnabled = true } } }, ...
By @ptornhult , This worked for me
This issue has been automatically marked as stale because it has not had recent activity. Please comment here if it is still valid so that we can reprioritize. Thank you!
the experimental motionEventSpy worked like a charm:
var columnScrollingEnabled: Boolean by remember { mutableStateOf(true) } ... LazyColumn(userScrollEnabled = columnScrollingEnabled) ... item { GoogleMap(Modifier.motionEventSpy { when (it.action) { MotionEvent.ACTION_DOWN -> { columnScrollingEnabled = false } MotionEvent.ACTION_UP -> { columnScrollingEnabled = true } } }, ...
Indeed it works fine. Tip for those who have a map nested in multiple composable layers, but don't want to pass state parameter through each. Use CompositionLocalProvider to incapsulate logic of accessing/providing current pressed state in a custom class.
TODO: update the docs / sample code to demonstrate this LazyColumn workaround.