3

We are having hard times to smoothly resize a here SDK map on Android.

We want to smoothly resize the map to the bottom sheet collapse and hidden state as shown in demo app

But as you can see it does not really resize instead its jumps to the new position while the map keeps its dimensions and does not scale.

And this is what we did:

...
<com.here.sdk.mapview.MapView
    android:id="@+id/map"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginBottom="@dimen/nine_grid_unit" />

<androidx.constraintlayout.widget.ConstraintLayout
    android:id="@+id/menuBottomSheet"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/white"
    android:clickable="true"
    android:elevation="@dimen/four_grid_unit"
    android:focusable="true"
    app:behavior_hideable="true"
    app:behavior_peekHeight="@dimen/thirtytwo_grid_unit"
    app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">

    <View
        android:id="@+id/tap_stop"
        android:layout_width="@dimen/nine_grid_unit"
        android:layout_height="@dimen/one_grid_unit"
        android:layout_marginTop="@dimen/one_grid_unit"
        android:background="@color/grey_light"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <edeka.digital.app.widget.SegmentedControlView
        android:id="@+id/tabSwitchSegmentedControl"
        android:layout_width="@dimen/thirtyfive_grid_unit"
        android:layout_height="wrap_content"
        android:paddingStart="@dimen/three_grid_unit"
        android:paddingEnd="@dimen/three_grid_unit"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/tap_stop"
        app:segmentCount="2"
        app:segmentTitles="@array/segment_titles_shop_search" />

</androidx.constraintlayout.widget.ConstraintLayout>
...

And code:

val bottomBehavior = BottomSheetBehavior.from(binding.menuBottomSheet)
    bottomBehavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
        val mapView = binding.map
        override fun onSlide(bottomSheet: View, slideOffset: Float) {

        }

        override fun onStateChanged(bottomSheet: View, newState: Int) {

            bottomSheetBehaviorObservable.onNext(newState)

            when (newState) {
                BottomSheetBehavior.STATE_COLLAPSED -> {
                    mapView.bottom = binding.menuBottomSheet.top
                    mapView.invalidate()

                }
                BottomSheetBehavior.STATE_HIDDEN -> {
                    mapView.bottom = binding.menuBottomSheet.top
                    mapView.invalidate()
                }
                else -> { /* void */
                }
            }
        }
    })

I would have expected some kind of resize() function or that it layouts itself if layout dimensions change.

What we really want is already implemented in HERE WeGo App. The whole maps scales (inc. here logo) if user swipes the bottom sheet:

Scaling Map in HERE WeGo

Can anyone help us out?

The demo shown in 1 can be found here:

https://github.com/edekadigital/heremaps-demo

3 Answers3

2

The best solution that I've found to achieve it is to add a new method:

private fun updateMapView(bottomSheetTop: Int) {
    val mapView = binding.map

    val principalY = Math.min(bottomSheetTop / 2.0, mapView.height / 2.0)
    mapView.camera.principalPoint = Point2D(mapView.width / 2.0, principalY)

    val logoMargin = Math.max(0, mapView.bottom - bottomSheetTop)
    mapView.setWatermarkPosition(WatermarkPlacement.BOTTOM_CENTER, logoMargin.toLong())
}

and call it in onSlide and onStateChanged like this:

updateMapView(bottomSheet.top)

Note that you need to have the HERE logo at the bottom center position, otherwise it can't use an adjustable margin.

I was also trying to resize the map view, but the results were unsatisfying. Here is the code if you want to give a try:

private fun updateMapView(bottomSheetTop: Int) {
    val mapView = binding.map
    mapView.layoutParams.height = bottomSheetTop
    mapView.requestLayout()
}
1

It looks like that your map view is covered by the sliding panel and is not redrawn during slide animation. It renders only when the state changes. You can try to add mapView.invalidate() in onSlide method, like this:

override fun onSlide(bottomSheet: View, slideOffset: Float) {
    mapView.invalidate()
}

However, to be sure if that's the actual reason, I would need to get and build your code.

Michal
  • 11
  • 1
  • Hi! Thanks for your answer. Actually, just invalidate on slide did not work. I edited my question and added a link to a github repo. May have look. Thanks – Alexander Knauf Jan 27 '21 at 10:28
1

I was able to get your code, compile and reproduce the bug. I've found two options to fix that, both tested on an emulator and a real device.

  1. Copy the code from state change handling code into onSlide method:

    override fun onSlide(bottomSheet: View, slideOffset: Float) {
        mapView.bottom = binding.menuBottomSheet.top
        mapView.invalidate()
    }
    
  2. Remove map view resizing and invalidating code at all. It basically makes the whole setupBottomSheet method redundant. Map view works correctly without resizing and it's a preferable way to fix it, as it involves less code and operations.

  • Thanks again for this approach. But I think my post is misunderstood. I added the desired behaviour as it is implemented in HERE WeGo Map. The whole map scales according to the camera – Alexander Knauf Feb 12 '21 at 15:07