54

I have one of the new MapFragments in a ScrollView. Actually it's a SupportMapFragment, but anyway. It works, but there are two problems:

  1. When scrolled, it leaves a black mask behind. The black covers exactly the area where the map was, except for a hole where the +/- zoom buttons were. See screenshot below. This is on Android 4.0.

  2. The view doesn't use requestDisallowInterceptTouchEvent() when the user interacts with the map to prevent the ScrollView intercepting touches, so if you try to pan vertically in the map, it just scrolls the containing ScrollView. I could theoretically derive a view class MapView and add that functionality, but how can I get MapFragment to use my customised MapView instead of the standard one?

Partial screenshot of scrolling issue

Ralf
  • 14,655
  • 9
  • 48
  • 58
Timmmm
  • 88,195
  • 71
  • 364
  • 509
  • 1
    "I have one of the new MapFragments in a ScrollView" -- I will be surprised if this works well. "how can I get MapFragment to use my customised MapView instead of the standard one?" -- you can't, AFAIK. You would have to create your own fragment for hosting your `MapView`. – CommonsWare Dec 06 '12 at 15:37
  • I'm also facing the same issue, but I'm using a raw MapView within a Fragment. Same problem, when scrolling in either a ScrollView or ViewPager the black mask is left behind. – Chris Horner Dec 10 '12 at 00:21
  • On my Nexus S (Android 4.1.2), I'm not getting this issue. However, I'm getting exactly the same issue on all Android 2.2-2.3 devices I've tested on. – Ralf Dec 14 '12 at 13:50

8 Answers8

53

Applying a transparent image over the mapview fragment seems to resolve the issue. It's not the prettiest, but it seems to work. Here's an XML snippet that shows this:

<RelativeLayout
        android:id="@+id/relativeLayout1"
        android:layout_width="match_parent"
        android:layout_height="300dp" >

        <fragment
            android:id="@+id/map"
            android:name="com.google.android.gms.maps.MapFragment"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"/>

        <ImageView
            android:id="@+id/imageView123"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:src="@drawable/temp_transparent" />         
</RelativeLayout>
walnut_head
  • 746
  • 6
  • 4
  • 4
    I can confirm that this works (although some parts of the screen still flickers. I ended up using a FrameLayout as parent, and a plain `` with `android:background="@android:color/transparent"` for the transparent view. – Ralf Dec 21 '12 at 11:11
  • 1
    thanks dude i refer so many not working but yours simple and great – appukrb Feb 21 '13 at 11:48
  • Is there any similar workaround when using MapView instead of MapFragment? – Jorge Mendez May 02 '15 at 00:30
36

For me adding a transparent ImageView did not help remove the black mask completely. The top and bottom parts of map still showed the black mask while scrolling.

So the solution for it, I found in this answer with a small change. I added,

android:layout_marginTop="-100dp"
android:layout_marginBottom="-100dp"

to my map fragment since it was vertical scrollview. So my layout now looked this way:

<RelativeLayout
    android:id="@+id/map_layout"
    android:layout_width="match_parent"
    android:layout_height="300dp">

    <fragment
        android:id="@+id/mapview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginTop="-100dp"
        android:layout_marginBottom="-100dp"
        android:name="com.google.android.gms.maps.MapFragment"/>

    <ImageView
        android:id="@+id/transparent_image"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@color/transparent" />

</RelativeLayout>   

To solve the second part of the question I set requestDisallowInterceptTouchEvent(true) for my main ScrollView. When the user touched the transparent image and moved I disabled the touch on the transparent image for MotionEvent.ACTION_DOWN and MotionEvent.ACTION_MOVE so that map fragment can take Touch Events.

ScrollView mainScrollView = (ScrollView) findViewById(R.id.main_scrollview);
ImageView transparentImageView = (ImageView) findViewById(R.id.transparent_image);

transparentImageView.setOnTouchListener(new View.OnTouchListener() {

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        int action = event.getAction();
        switch (action) {
           case MotionEvent.ACTION_DOWN:
                // Disallow ScrollView to intercept touch events.
                mainScrollView.requestDisallowInterceptTouchEvent(true);
                // Disable touch on transparent view
                return false;

           case MotionEvent.ACTION_UP:
                // Allow ScrollView to intercept touch events.
                mainScrollView.requestDisallowInterceptTouchEvent(false);
                return true;

           case MotionEvent.ACTION_MOVE:
                mainScrollView.requestDisallowInterceptTouchEvent(true);
                return false;

           default: 
                return true;
        }   
    }
});

This worked for me. Hope it helps you..

Community
  • 1
  • 1
Laksh
  • 6,717
  • 6
  • 33
  • 34
8

This probably has its roots in the same place at causes the problem in this question. The solution there is to use a transparent frame, which is a little lighter weight than a transparent image.

Community
  • 1
  • 1
iagreen
  • 31,470
  • 8
  • 76
  • 90
5

Done after lots of R&D:

fragment_one.xml should looks like:

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/scrollViewParent"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="400dip" >

            <com.google.android.gms.maps.MapView
                android:id="@+id/mapView"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />

            <View
                android:id="@+id/customView"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:background="@android:color/transparent" />
        </RelativeLayout>

        <!-- Your other elements are here -->

    </LinearLayout>

</ScrollView>

Your Java class of FragmentOne.java looks like:

private GoogleMap mMap;
private MapView mapView;
private UiSettings mUiSettings;
private View customView

onCreateView

mapView = (MapView) rootView.findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);

if (mapView != null) {
   mMap = mapView.getMap();
   mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
   mUiSettings = mMap.getUiSettings();
   mMap.setMyLocationEnabled(true);
   mUiSettings.setCompassEnabled(true); 
   mUiSettings.setMyLocationButtonEnabled(false);
}


scrollViewParent = (ScrollView)rootView.findViewById(R.id.scrollViewParent);
customView = (View)rootView.findViewById(R.id.customView);

customView.setOnTouchListener(new View.OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                int action = event.getAction();
                switch (action) {
                    case MotionEvent.ACTION_DOWN:
                        // Disallow ScrollView to intercept touch events.
                        scrollViewParent.requestDisallowInterceptTouchEvent(true);
                        // Disable touch on transparent view
                        return false;

                    case MotionEvent.ACTION_UP:
                        // Allow ScrollView to intercept touch events.
                        scrollViewParent.requestDisallowInterceptTouchEvent(false);
                        return true;

                    case MotionEvent.ACTION_MOVE:
                        scrollViewParent.requestDisallowInterceptTouchEvent(true);
                        return false;

                    default:
                        return true;
                }
            }
        });
Hiren Patel
  • 52,124
  • 21
  • 173
  • 151
  • I had the added complexity of sitting inside a nested widget structure. But i finally found my way out by using your solution. (my scroll view was only reachable by using view.getParent()) – Spidfire May 26 '15 at 09:39
  • 1
    works like charm,helped me when the top most voted answer failed in my case..thank you. – Sachin Varma Feb 17 '17 at 09:58
2

I used this structures and I overcame the problem.

I used a container view for maps fragment.

<ScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:text="Another elements in scroll view1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />


        <com.erolsoftware.views.MyMapFragmentContainer
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="250dp">

            <fragment
                xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:tools="http://schemas.android.com/tools"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:id="@+id/eventMap"
                tools:context="com.erolsoftware.eventapp.EventDetails"
                android:name="com.google.android.gms.maps.SupportMapFragment"/>

        </com.erolsoftware.views.MyMapFragmentContainer>

        <TextView
            android:text="Another elements in scroll view2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />



    </LinearLayout>




</ScrollView>

The container class:

public class MyMapFragmentContainer extends LinearLayout {


    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev)
    {
        if (ev.getActionMasked() == MotionEvent.ACTION_DOWN)
        {
            ViewParent p = getParent();
            if (p != null)
                p.requestDisallowInterceptTouchEvent(true);
        }

        return false;
    }

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

    public MyMapFragmentContainer(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MyMapFragmentContainer(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

}
Erkan Erol
  • 1,334
  • 2
  • 15
  • 32
2

No need to struggle with customScrollViews and transparent layout files. simply use lighter version of google map and your issue will be resolved.

  map:liteMode="true"

add above property inside map fragment in your layout file. and issue will be fixed.

Developine
  • 12,483
  • 8
  • 38
  • 42
0

For the second part of the question - you can derive a fragment class from SupportMapFragment, and use that in your layout instead. You can then override Fragment#onCreateView, and instantiate your custom MapView there.

If that does not work, you can always create your own fragment - then you just need to take care of calling all the lifecycle methods yourself (onCreate, onResume, etc). This answer has some more details.

Community
  • 1
  • 1
Ralf
  • 14,655
  • 9
  • 48
  • 58
0
<ScrollView
            android:layout_width="match_parent"
    ::
    ::
    ::
      <FrameLayout
            android:id="@+id/map_add_business_one_rl"
            android:layout_width="match_parent"
            android:layout_height="100dp"
         >
                        <fragment

                            android:id="@+id/map"
                            android:name="com.google.android.gms.maps.SupportMapFragment"
                            android:layout_width="match_parent"
                            android:layout_height="match_parent"
                            android:layout_marginTop="-100dp"
                            android:layout_marginBottom="-100dp"

                            />

        </FrameLayout>

    ::
    ::
    ::
     </ScrollView>
Fakhar
  • 3,946
  • 39
  • 35