android-maps-compose icon indicating copy to clipboard operation
android-maps-compose copied to clipboard

Marker drag event callback

Open chibatching opened this issue 2 years ago • 15 comments

I want to get marker drag event callback and manipulate marker-related work.

So, Marker composable have to have dragging callback parameter like onMarkerDrag onMarkerDragStart onMarkerDragEnd similar with onClick and onInfoWindow~

It is an alternative to OnMarkerDragListener of Android view version.

chibatching avatar Feb 06 '22 08:02 chibatching

@chibatching Thank you for opening this issue. 🙏 Please check out these other resources that might be applicable:

This is an automated message, feel free to ignore.

jpoehnelt avatar Feb 06 '22 08:02 jpoehnelt

This is what MarkerDragState is for. You should be able to do the following:

val markerDragState = rememberMarkerDragState()

GoogleMap() {
    Marker(
        draggable = true,
        markerDragStae = markerDragState,
        // ...
    )
}
Text(text = "The marker drag state is $markerDragState.dragState")

Definitely open to reevaluate this although I think marker drag state should only be observed either using the State-based approach or the callback-based approach, not both. Please provide a bit more context if for some reason the latter works better for your use case.

arriolac avatar Feb 07 '22 18:02 arriolac

@arriolac I have to know marker LatLng after drag to execute some process using the position after the move. It is not enough to observe only the drag state.

My usecase is like below

var markerPoint by remember { mutableStateOf(defaultLatLng) }

GoogleMap() {
    Marker(
        position = markerPoint,
        draggable = true,
        onMarkerDragEnd = { marker ->
            markerPoint = maker.position
            viewModel.updateUserSelectedPosition(marker.position)
        },
    )
}

chibatching avatar Feb 07 '22 23:02 chibatching

I think it doesn't need to be a callback style if the drag state has marker object or position info.

chibatching avatar Feb 07 '22 23:02 chibatching

I think it doesn't need to be a callback style if the drag state has marker object or position info.

Yeah, this is what I'm thinking as well. There should be a Marker property in the MarkerDragState object. Will add that.

arriolac avatar Feb 07 '22 23:02 arriolac

I updated my PR #11 to add Marker property. Would you check it?

chibatching avatar Feb 08 '22 05:02 chibatching

Please see my comment on https://github.com/googlemaps/android-maps-compose/pull/11#issuecomment-1035586376 for how this feature should be implemented.

arriolac avatar Feb 10 '22 22:02 arriolac

AFAICT the current implementation (in 2.2.0) does not take into account the difference between drag state and drag events. The onMarkerDrag... callbacks reflect events, while the current 'MarkerState' approach reflects state. This implies information loss; some or all drag events may never be seen by an observer. An approach like this may be reasonable when there is only a single type of event, DRAG, but there are 3 different types, and an observer may never notice that the marker was dragged, as START, and DRAG, may fall through the cracks; even a distinct END may not be seen by a slow observer when another drag event starts quickly. Really, the only thing I can observe here is whether I am currently dragging or not, essentially binary drag state.

For example, I have a use case where a user's marker drag events are not committed to the data model when the marker is dragged to an invalid position. This looks hard to implement reliably at the moment, if possible at all; I need to save the prior marker position at drag START, verify the final position at drag END and commit or roll back, and update dependent visualizations upon DRAG. I don't see a way to access the raw events via a listener, either. This use case causes zero problems with the standard GoogleMap event listener approach.

What you want to expose here is a Flow or possibly a ReceiveChannel of drag events. The consumer will have to determine the buffering strategy, not the compose wrapper.

bubenheimer avatar Jun 04 '22 19:06 bubenheimer

There also seems to be a misconception about what state hoisting means. When I hoist state, I control the state at a higher level of the composition, and the state object is not present at deeper levels of the composition, which cannot directly change the state. Yet here I am expected to pass the "hoisted" state object down into the composition, and it will change under my nose when the user drags the marker. That is the exact opposite of state hoisting. It means a lot of trouble for my outside data model.

https://googlemaps.github.io/android-maps-compose/maps-compose/com.google.maps.android.compose/-marker-state/

A state object that can be hoisted to control and observe the marker state.

bubenheimer avatar Jun 05 '22 01:06 bubenheimer

@bubenheimer thanks for the feedback on the current marker drag API. I'm a bit confused what you mean by information loss as all marker drag transition states should be reported in MarkerState.dragState—maybe I'm missing something?

From your feedback, seems like it is desirable to have an event-based API to accomplish validation type actions as the current state-based approach for drag state is difficult to work with. If you can capture some suggestions you have on a separate issue we can reevaluate and improve upon the existing API.

arriolac avatar Jun 06 '22 21:06 arriolac

Thanks. In general there is no way to guarantee that an observer will see transitory states of a MutableState, the observer only gets to see snapshot state (not events), and it may not even see all of the snapshot states. This is a fundamental characteristic of snapshot state. For background, see the bottom of the snapshotFlow documentation:

Observable state is a lossy compression of the events that produced that state.

https://developer.android.com/reference/kotlin/androidx/compose/runtime/package-summary#snapshotFlow(kotlin.Function0)

I will propose something in a separate issue.

Edit: removed comment about "state object hoisting" in favor of broader discussion in new issue.

bubenheimer avatar Jun 06 '22 21:06 bubenheimer

Hope we will see this event soon, both drag start and drag end. I could do with drag start but drag end is critical.

zaheeroz avatar Sep 23 '22 10:09 zaheeroz

@zaheeroz You may be able to "reconstruct" drag start & end to some degree from the information that is available, but you need to take into account that you may miss some ends and/or starts, when a new start-drag-end cycle starts too quickly after the last one ends.

bubenheimer avatar Sep 23 '22 14:09 bubenheimer

Thanks @bubenheimer that's great. Could you provide a link that can help in this regard. I can start a drag by first clicking on the marker to register a 'drag start' then drag the marker. But the problem is even click fires on 'pressed' and not ' on release' so I cant get the location where the marker was dragged (end of drag). So any help in this regard will be greatly appreciated.

zaheeroz avatar Sep 24 '22 07:09 zaheeroz

@zaheeroz I don't have a link, sorry.

bubenheimer avatar Sep 24 '22 08:09 bubenheimer

I believe the initial request here was addressed in v2.0, so closing this issue. Conversation continues about improving marker drag state in #149.

wangela avatar Feb 07 '23 00:02 wangela