Search code examples
androidkotlingoogle-mapssupportmapfragment

disable scrollview when panning map


I am VERY new to android programming and even newer to kotlin, but I am trying to implement a simple activity as a proof of concept where a map fragment is part of a scrollable list that will later be used to capture user information (and a marker location on the map).

I used a google developer tutorial to get my map fragment to display the map, and I've now embedded that map fragment inside a scroll view. Everything works except for the fact that when I try to pan my map vertically (north/south), my scroll view starts to scroll.

How do I prevent the scrollview from moving if I touch on the map fragment area? Thanks in advance for the help!

Here is the XML code of the activity:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <ScrollView

        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fillViewport="true">

        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/colorAccent">

            <TextView
                android:id="@+id/textView2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="24dp"
                android:text="TextView1"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent" />

            <EditText
                android:id="@+id/editTextTextPersonName"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="60dp"
                android:ems="10"
                android:inputType="textPersonName"
                android:text="Name"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintHorizontal_bias="0.497"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/textView2" />

            <TextView
                android:id="@+id/textView3"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="172dp"
                android:text="TextView"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintHorizontal_bias="0.498"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/editTextTextPersonName" />

            <fragment
                android:id="@+id/map_fragment"
                class="com.google.android.gms.maps.SupportMapFragment"
                android:layout_width="match_parent"
                android:layout_height="300dp"
                android:layout_marginTop="28dp"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintHorizontal_bias="0.0"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/textView3" />

            <TextView
                android:id="@+id/textView4"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="200dp"
                android:layout_marginBottom="16dp"
                android:text="HELLO WORLD DOWN HERE"
                android:textSize="20sp"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintHorizontal_bias="0.497"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/map_fragment" />


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

</LinearLayout>

and here is the koitlin activity MainActivity.kt:

// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.codelabs.buildyourfirstmap

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.SupportMapFragment
import com.google.android.gms.maps.UiSettings
import com.google.android.gms.maps.model.LatLngBounds
import com.google.android.gms.maps.model.MarkerOptions
import com.google.codelabs.buildyourfirstmap.place.Place
import com.google.codelabs.buildyourfirstmap.place.PlacesReader

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val mapFragment = supportFragmentManager.findFragmentById(R.id.map_fragment) as? SupportMapFragment

        mapFragment?.getMapAsync {
                googleMap->addMarkers(googleMap)
        }

        mapFragment?.getMapAsync { googleMap ->
            // Ensure all places are visible in the map.
            googleMap.setOnMapLoadedCallback {
                val bounds = LatLngBounds.builder()
                places.forEach { bounds.include(it.latLng) }
                googleMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds.build(), 20))
                val uisettings = googleMap.uiSettings
                googleMap.uiSettings.isZoomControlsEnabled = true

            }

        }

    }

    private val places: List<Place> by lazy {
        PlacesReader(this).read()
    }

    /**
     * Adds marker representations of the places list on the provided GoogleMap object
     */
    private fun addMarkers(googleMap: GoogleMap) {
        places.forEach { place ->
            val marker = googleMap.addMarker(
                MarkerOptions()
                    .title(place.name)
                    .position(place.latLng)
            )

        }
    }
}


Solution

  • You should add these lines as soon as map is ready:

    googleMap.setOnCameraMoveStartedListener(OnCameraMoveStartedListener { i ->
        if (i == OnCameraMoveStartedListener.REASON_GESTURE) {
            blockScrollView()
        }
    })
    
    googleMap.setOnCameraMoveCanceledListener(OnCameraMoveCanceledListener { enableScrollView() })
    

    Declare your scrollview and disable, enable it inside blockScrollView(), enableScrollView() methods.

    Optional step: Declare GoogleMap map; at class level and initialize googleMap in getMapAsync method to it. And use map instead of calling getMapAsync every time you use map. Calling getMapAsync multiple times is wrong.