ViewPager with Google Maps API v2: mysterious black view

AndroidGoogle MapsAndroid Viewpager

Android Problem Overview


I have integrated the new google maps api v2 fragment in a view pager. When scrolling from the map fragment, a black view overlaps the adjacent fragments. Someone has solved?

Edit: screenshot

enter image description here

public static class PagerAdapter extends FragmentPagerAdapter{
	
    public PagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public int getCount() {
        return NUM_ITEMS;
    }

    @Override
    public Fragment getItem(int position) {
    	
    	Fragment pageFragment;
    	
        switch (position) {
		case 0:
			pageFragment = new TabAFragment();
			break;
			
		case 1:
			pageFragment = new TabBFragment();
			break;
			
		case 2:
			pageFragment = SupportMapFragment.newInstance();
			break;

		default:
			pageFragment = null;
			break;
		}
        
        return pageFragment;
    }
}

Android Solutions


Solution 1 - Android

I was able to stop the black surface being left behind after transition by placing another view with a transparent background on top of the ViewPager inside a FrameLayout:

<FrameLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
 
    <android.support.v4.view.ViewPager
        android:id="@+id/fragment_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
    </android.support.v4.view.ViewPager>

    <!-- hack to fix ugly black artefact with maps v2 -->
    <FrameLayout 
        android:layout_width="match_parent"
        android:layout_height="match_parent" 
        android:background="@android:color/transparent" />
  
</FrameLayout>

Solution 2 - Android

Had the same problem with SlidingMenu and ViewPager. I noticed that control buttons in map fragment are not black in the left behind artifact. I solved the problem by overriding the onCreateView() method of MapFragment (SupportMapFragment)

@Override
public View onCreateView(LayoutInflater inflater, 
                         ViewGroup view, 
                         Bundle savedInstance) {

    View layout = super.onCreateView(inflater, view, savedInstance);
    FrameLayout frameLayout = new FrameLayout(getActivity());
    frameLayout.setBackgroundColor(
        getResources().getColor(android.R.color.transparent));
    ((ViewGroup) layout).addView(frameLayout,
        new ViewGroup.LayoutParams(
            LayoutParams.FILL_PARENT, 
            LayoutParams.FILL_PARENT
        )
    );
    return layout;
}

Solution 3 - Android

Google released a fix for this, but only for 4.1+ (You don't need to download a new version of PlayServices, they used a server side flag)

Here's what I'm using to bypass the issue - Ensures you don't waste any CPU cycles on devices >= 4.1

public class FixMapFragment extends SupportMapFragment {

    @Override
    public View onCreateView(LayoutInflater inflater, 
                             ViewGroup container, 
                             Bundle savedInstanceState) {

        View view = super.onCreateView(inflater, container, savedInstanceState);

        // Fix for black background on devices < 4.1
        if (android.os.Build.VERSION.SDK_INT < 
            android.os.Build.VERSION_CODES.JELLY_BEAN) {
            setMapTransparent((ViewGroup) view);
        }
        return view;
    }

    private void setMapTransparent(ViewGroup group) {
        int childCount = group.getChildCount();
        for (int i = 0; i < childCount; i++) {
            View child = group.getChildAt(i);
            if (child instanceof ViewGroup) {
                setMapTransparent((ViewGroup) child);
            } else if (child instanceof SurfaceView) {
                child.setBackgroundColor(0x00000000);
            }
        }
    }
}

Solution 4 - Android

My workaround: make use of the new snapshot interface from GoogleMap and display a snapshot of the map while scrolling the page.

Here is my code to setting the snapshot (it's in the same fragment as map, called FragmentMap.java):

public void setSnapshot(int visibility) {
	switch(visibility) {
	case View.GONE:
		if(mapFragment.getView().getVisibility() == View.VISIBLE) {
			getMap().snapshot(new SnapshotReadyCallback() {
				@Override
				public void onSnapshotReady(Bitmap arg0) {
					iv.setImageBitmap(arg0);
				}
			});
			iv.setVisibility(View.VISIBLE);
			mapFragment.getView().setVisibility(View.GONE);
		}
		break;
	case View.VISIBLE:
		if(mapFragment.getView().getVisibility() == View.GONE) {
			mapFragment.getView().setVisibility(View.VISIBLE);
			iv.setVisibility(View.GONE);
		}
		break;
	}
}

Where "mapFragment" is my SupportedMapFragment and "iv" is an ImageView (make it match_parent).

And here I am controlling the scroll:

pager.setOnPageChangeListener(new OnPageChangeListener() {
		@Override
		public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
			if(position == 0 && positionOffsetPixels > 0 || position == 1 && positionOffsetPixels > 0) {
				((FragmentMap)adapter.getRegisteredFragment(1)).setSnapshot(View.GONE);
			} else if(position == 1 && positionOffsetPixels == 0) {
				((FragmentMap)adapter.getRegisteredFragment(1)).setSnapshot(View.VISIBLE);
			}
		}
		@Override
		public void onPageScrollStateChanged(int arg0) {}
		@Override
		public void onPageSelected(int arg0) {}
	});

My fragment with map (FragmentMap) is on position 1, so I need to controll the scroll from position 0 to 1 and from position 1 to 2 (the first if-clause). "getRegisteredFragment()" is a function in my custom FragmentPagerAdapter, in which I have a SparseArray(Fragment) called "registeredFragments".

So, whenever you scroll to or from your map, you always see a snapshot of it. This works very well for me.

Solution 5 - Android

I had same issue of black screen on scrolling of list view, i was using map fragment with list view in same screen i have resolved this issue with use of the magical property in xml where i am talking list view just we have to put android:scrollingCache="false".my issue is fixed try this property to stop lagging and flickering in your maps.

Solution 6 - Android

You haven't given much detail so there is only so much I can suggest. I had a similar issue that the screen flickered between views in the pager. It turned out to be the mapView inflating when swapping between pages the first time.

To be clear I had 3 pages in my pager and my map was the last page.

To solve this I found that setting the number of off screen pages to 2 (this worked in the case above) that when my fragment started it loaded all the views at once.

See http://developer.android.com/reference/android/support/v4/view/ViewPager.html#setOffscreenPageLimit (int)

Solution 7 - Android

There is one more solution to this problem. I am showing MapFragment within another fragment. The MapFragment is dynamically added into the a FrameLayout.

The solution is to use frameLayout.setVisibility(View.Visible) and frameLayout.setVisibility(View.Gone) on open and close events of sliding menu. It dosent require an extra view to be added. And the black area is completely gone.

getSlidingMenu().setOnOpenListener(
		new OnOpenListener() {
			@Override
			public void onOpen() {
				frameLayout.setVisibility(View.GONE);
			}
		});

getSlidingMenu().setOnClosedListener(
		new OnClosedListener() {

			@Override
			public void onClosed() {
				frameLayout.setVisibility(View.VISIBLE);
			}
		});

Solution 8 - Android

None of the methods above worked for me, not even others I've found elsewhere. Finally, I chose a partial solution. I listen on page changes via the ViewPager's onPageChangeListener, and hide the map when its page starts scrolling, and likewise show it again when it stops scrolling. I also have added a white View to be displayed when scrolling.

Solution 9 - Android

Just copy my custom map fragment to your project. And if you have black lines with ScrollView on top and bottom set to your ScrollView android:fadingEdge="none"

public class CustomMapFragment extends SupportMapFragment {
private OnActivityCreatedListener onActivityCreatedListener;

public CustomMapFragment() {
}

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

    FrameLayout frameLayout = new FrameLayout(getActivity());
    frameLayout.setBackgroundColor(getResources().getColor(android.R.color.transparent));
    ((ViewGroup) layout).addView(frameLayout,
            new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
    return layout;
}

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    if (getOnActivityCreatedListener() != null)
        getOnActivityCreatedListener().onCreated();
}

public OnActivityCreatedListener getOnActivityCreatedListener() {
    return onActivityCreatedListener;
}

public void setOnActivityCreatedListener(
        OnActivityCreatedListener onActivityCreatedListener) {
    this.onActivityCreatedListener = onActivityCreatedListener;
}

public interface OnActivityCreatedListener {
    void onCreated();
}

}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPepeView Question on Stackoverflow
Solution 1 - AndroidJeff GilfeltView Answer on Stackoverflow
Solution 2 - AndroidLubos HoracekView Answer on Stackoverflow
Solution 3 - AndroidTspoonView Answer on Stackoverflow
Solution 4 - AndroidNamenlosView Answer on Stackoverflow
Solution 5 - Androiduser1414160View Answer on Stackoverflow
Solution 6 - AndroidGraham SmithView Answer on Stackoverflow
Solution 7 - AndroidJehandadKView Answer on Stackoverflow
Solution 8 - AndroidazyootView Answer on Stackoverflow
Solution 9 - Androiduser2728452View Answer on Stackoverflow