ViewPager with Google Maps API v2: mysterious black view
Asked Answered
C

9

95

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;
    }
}
Cody answered 12/12, 2012 at 10:28 Comment(4)
Does it happen an more than one device? Maybe a few code lines from you ViewPager and map implementation might help to better understand your problem.Bullion
Yes, happens on all devices I tried: samsung, htc, android 4.0, 2.3, etc. I have integrated the map in my app, and in a clean little app with only the pager and map, with the same result.Cody
@Pepe, would you please say, how you get GoogleMap object from the ViewPager? Stuck on this for weeks. If you didn't understand well question, then look up my question, you'll find my post. Please, reply.Lungi
I want to add that when doing a screen record the issue doesn't seem to happen.Questor
O
117

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>
Olivenite answered 17/12, 2012 at 8:4 Comment(13)
Great! It is not perfect, because sometimes while moving pager appears part of the black view. But now it not remains in screen any more. Thanks! (do you have any explanation for this hack?)Cody
Not really. I just noticed where the zoom and location controls sat on top of the map surface the black trail did not appear, so I placed a view on top to cover the entire map and it worked. I agree it is not perfect - the black background seems to be part of the GLSurfaceView window code.google.com/p/gmaps-api-issues/issues/detail?id=4639Olivenite
Seems like it fixed my ViewPager issue. Thanks, but it looks like I have a similar issue w/ a SlideMenu (left menu like G+/Yahoo), doing the same thing.. Any thoughts on fixing a SlideMenu implementation?Vasques
@Vasques don't animate the container, use the animation only on the side menu, it fixed it for me.Mccormack
My solution fixed both slidemenu and viewpagerBakehouse
@Mccormack Care to be more specific and link a snippet example?Darby
This didn't fix it, but improved it for me. I am looking for a better solution, but this is a OK work around for the time being.Tippet
Ive done this and the below programmatic solution, they work while the app is in the foreground but when the app is closed and still running and you go back to it the map stays on top still..Salami
this works! the flicker is still there, but at least the entire page doesnt go black like it did before. the map still isnt perfect, but thanks to this its at least release-able!Kuopio
I think this issue is no more existing in new google maps application, any idea will it work for apps also?Pustulate
You've saved me ! Thanks! You've got a fresh beer waiting for u :)Ecumenism
Thanks a lot! Great answer but although google should solve this problemAdjective
Thank you very much! You save lots of time of mine as well as others :)Wilmerwilmette
B
43

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;
}
Bakehouse answered 21/12, 2012 at 16:23 Comment(5)
I use it for SlidingMenu too. But I have the flickering issue (with the sliding animation) and it's unacceptable, looks awful. Do you have it too? I tested on HTC One S. What is interesting, I only have this issue with the opening animation and not when closing SlidingMenuUlrike
None of the fixes worked for me. I have practically the same issue as Michal K. Using SlidingMenu and opening or closing slowly at a continuous speed and there is no problem. Fling open or press back to close the window and it looks like the map lags a bit leaving a blank space until the slide finishes where the map returns to its proper position.Darby
@qubz: About the 'sliding menu' try animating the menu, and not the map. It solved the problem for me, if the map is not moving.Mccormack
@meh: The map may be moving while I'm opening/closing the SlidingMenu. By moving I mean CameraUpdate. I'll see if I can pause the animation, though this is going to hinder UX.Darby
@Lubos Horacek : Could you please post a sample code.I am getting Null pointer exception error..Imogene
B
7

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);
            }
        }
    }
}
Billups answered 19/10, 2013 at 9:28 Comment(4)
I guess you reference the class as follows: FixMapFragment mapFragment = (FixMapFragment) fragmentManager.findFragmentById(R.id.map); and in the layout file: <fragment android:id="@+id/map" android:name="com.example.fragments.FixMapFragment" .... Though, the map still flickers as far as I can tell (Android 4.0.4).Inconvertible
@Inconvertible i have a mapview that flickers, is there a way to solve that ?Attaway
@Rat-a-tat-a-tatRatatouille There is no reliable workaround to avoid the flickering of the map view as far as I know.Inconvertible
i dont know if what i have done for now is correct or not but it works. i set the mapview visibility to invisible and then after some seconds set the mapviews visibility back to visible. reduces the flicker.Attaway
S
6

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.

Suilmann answered 14/8, 2013 at 11:14 Comment(1)
The other answers did not work for me - this is the only one that worked. Thanks!Beady
A
4

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.

Azpurua answered 22/4, 2013 at 9:48 Comment(0)
F
2

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)

Future answered 12/12, 2012 at 10:39 Comment(3)
Thanks, but not worked. The problem is that the part of screen covered by map, when change to other fragment, remains black, covering the view of this other fragment.Cody
hmmm interesting. I shall have a think on this.Future
I cannot find setOffscreenPageLimit on that page yu linked toJacobah
J
0

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);
            }
        });
Jovitta answered 2/3, 2013 at 9:17 Comment(0)
G
0

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.

Georgettageorgette answered 29/5, 2013 at 22:32 Comment(1)
It can be further extended to capture the View's current image to a bitmap, and then display it on an ImageView while the pager is scrolling. That way, users wouldn't notice the hack behind it. However, I found this computation a bit too expensive as it would slow down the UI's response to the swiping.Georgettageorgette
B
-2

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();
}

}

Blindfold answered 26/9, 2013 at 7:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.