How to Make Android Map Scrollable Inside a ScrollView Layout

Technically, placing a map view  inside a ScrollView layout container can make the map becoming difficult to scroll. This is because the scrollable layout container will intercept the touch event so the map will lose the touch event, making it difficult to scroll or pan. This happens either on Android Map V2 or the previous versions.

In this case, i work with the SupportMapFragment in Android Map V2 so the workaround is to make a custom SupportMapFragment class so we can override its touch event. This solution is based on gaucho’s answer on related post in stackoverflow with some small changes made by me.

WorkaroundMapFragment.java

package net.londatiga.android.ui.fragment;

import android.content.Context;
import android.os.Bundle;
import android.widget.FrameLayout;

import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;

import com.google.android.gms.maps.SupportMapFragment;

public class WorkaroundMapFragment extends SupportMapFragment {
	private OnTouchListener mListener;

    @Override
    public View onCreateView(LayoutInflater layoutInflater, ViewGroup viewGroup, Bundle savedInstance) {
        View layout = super.onCreateView(layoutInflater, viewGroup, savedInstance);

        TouchableWrapper frameLayout = new TouchableWrapper(getActivity());

        frameLayout.setBackgroundColor(getResources().getColor(android.R.color.transparent));

        ((ViewGroup) layout).addView(frameLayout,
                new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));

        return layout;
    }

    public void setListener(OnTouchListener listener) {
    	mListener = listener;
    }

    public interface OnTouchListener {
    	public abstract void onTouch();
    }

    public class TouchableWrapper extends FrameLayout {

      public TouchableWrapper(Context context) {
        super(context);
      }

      @Override
      public boolean dispatchTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
          case MotionEvent.ACTION_DOWN:
        	  mListener.onTouch();
                break;
          case MotionEvent.ACTION_UP:
        	  mListener.onTouch();
                break;
        }
        return super.dispatchTouchEvent(event);
      }
    }
}

In this class, we intercept the touch event by using TouchableWrapper class that extends the FrameLayout. There is also a custom listener OnTouchListener to dispatch the touch event to the main activity MyMapActivity that handles the map. When touch event occured, dispatchTouchEvent will be called and the listener mListener will handle it.

The ScrollView layout container, fragment_my_map.xml

<?xml version="1.0" encoding="UTF-8"?>
<ScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/sv_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <!-- other child views //-->
     <fragment
        android:tag="fragment_map"
       android:id="@+id/fragment_map"
       android:layout_width="match_parent"
       android:layout_height="175dp"
       android:layout_marginTop="@dimen/activity_horizontal_margin"
       class="net.londatiga.android.ui.fragment.WorkaroundMapFragment"/>
</ScrollView>

Inside map activity that uses the map, MyMapActivty.java

package net.londatiga.android.ui;

import net.londatiga.android.ui.fragment.WorkaroundMapFragment;
import com.google.android.gms.maps.GoogleMap;
import android.widget.ScrollView;

public class MyMapActivty extends MapActivity {
    private ScrollView mScrollView;
    private GoogleMap mMap;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.fragment_my_map);

        mMap = ((WorkaroundMapFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_map)).getMap();
        mScrollView = (ScrollView) findViewById(R.id.sv_container);

       ((WorkaroundMapFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_map)).setListener(new WorkaroundMapFragment.OnTouchListener() {
          @Override
          public void onTouch() {
              mScrollView.requestDisallowInterceptTouchEvent(true);
          }
     });
   }
}

Inside activity class, get the GoogleMap mMap and ScrollView container mScollView then set the OnTouchListener to the WorkaroundMapFragment. When touch event occured,  onTouch handler will be called and we block the event being dispatched the ScrollView layout. This will make the map scrollable without the ScrollView being scrollable too.

facebooktwittergoogle_plusredditpinterestlinkedinmailby feather

Comments

  1. Sanket says

    Above code is working good but one another problem arise google map controller inner ZoomIn,ZoomOut(+,-) sign not working when click

  2. Philip Trowe says

    Check out my blog. The following post includes a video that shows you how to create an Android smartphone application that displays a vertically scrolling list of countries on the screen. The application is created using the Eclipse IDE and Android SDK. It features an “OK” button at the bottom of the screen that, when pressed, terminates the application.

    In the process of making this Android application you will encounter the following SDK object types, etc:
    • ScrollView,
    • Button,
    • View,
    • TableLayout,
    • TableRow,
    • OnClickListener,
    • TextView,
    • Colours in Android represented by hexadecimal numbers.

    http://androidprogrammeringcorner.blogspot.com/2015/03/pak-longs-android-programming-corner.html

    Best regards,

    Philip

Leave a Reply

Your email address will not be published. Required fields are marked *