ViewPager mit Google Maps API v2: mysteriöse schwarze Ansicht


95

Ich habe das neue Fragment von Google Maps API v2 in einen View Pager integriert. Beim Scrollen vom Kartenfragment überlappt eine schwarze Ansicht die benachbarten Fragmente. Jemand hat gelöst?

Bearbeiten: Screenshot

Geben Sie hier die Bildbeschreibung ein

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

Kommt es bei mehr als einem Gerät vor? Möglicherweise helfen ein paar Codezeilen von Ihrem ViewPager und der Kartenimplementierung, Ihr Problem besser zu verstehen.
Adinia

Ja, passiert auf allen Geräten, die ich ausprobiert habe: Samsung, HTC, Android 4.0, 2.3 usw. Ich habe die Karte in meine App und in eine saubere kleine App mit nur Pager und Karte integriert, mit dem gleichen Ergebnis.
Pepe

@Pepe, würdest du bitte sagen, wie du GoogleMapObjekt von der bekommst ViewPager? Ich habe wochenlang daran festgehalten. Wenn Sie die Frage nicht gut verstanden haben, schlagen Sie meine Frage nach, Sie finden meinen Beitrag. Bitte antworte.
Azizbekian

Ich möchte hinzufügen, dass screen recorddas Problem bei einem Vorgang nicht auftritt.
Theblang

Antworten:


115

Ich konnte verhindern, dass die schwarze Oberfläche nach dem Übergang zurückbleibt, indem ich eine weitere Ansicht mit transparentem Hintergrund oben auf der ViewPagerInnenseite platzierte. 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>

1
Toll! Es ist nicht perfekt, da manchmal beim Bewegen des Pagers ein Teil der schwarzen Ansicht erscheint. Aber jetzt bleibt es nicht mehr auf dem Bildschirm. Vielen Dank! (Haben Sie eine Erklärung für diesen Hack?)
Pepe

7
Nicht wirklich. Ich habe gerade bemerkt, wo sich die Zoom- und Positionssteuerung oben auf der Kartenoberfläche befand. Die schwarze Spur wurde nicht angezeigt. Deshalb habe ich eine Ansicht oben platziert, um die gesamte Karte abzudecken, und es hat funktioniert. Ich bin damit einverstanden, dass es nicht perfekt ist - der schwarze Hintergrund scheint Teil des GLSurfaceView-Fensters code.google.com/p/gmaps-api-issues/issues/detail?id=4639 zu sein
Jeff Gilfelt

5
Scheint, als hätte es mein ViewPager-Problem behoben. Danke, aber es sieht so aus, als hätte ich ein ähnliches Problem mit einem SlideMenu (linkes Menü wie G + / Yahoo), das dasselbe tut. Irgendwelche Gedanken zur Behebung einer SlideMenu-Implementierung?
Chrispix

@Chrispix animiert den Container nicht, verwendet die Animation nur im Seitenmenü, sie wurde für mich behoben.
meh

1
Ich habe dies und die folgende programmatische Lösung getan, sie funktionieren, während die App im Vordergrund steht, aber wenn die App geschlossen ist und noch läuft und Sie zurückkehren, bleibt die Karte immer noch oben.
L7ColWinters

43

Hatte das gleiche Problem mit SlidingMenu und ViewPager. Ich habe festgestellt, dass die Steuerschaltflächen im Kartenfragment im linken Artefakt nicht schwarz sind. Ich habe das Problem gelöst, indem ich die onCreateView()Methode von überschrieben habeMapFragment (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;
}

Ich benutze es auch für SlidingMenu. Aber ich habe das flackernde Problem (mit der gleitenden Animation) und es ist inakzeptabel, sieht schrecklich aus. Hast du es auch Ich habe auf dem HTC One S getestet. Was interessant ist, ich habe nur dieses Problem mit der Eröffnungsanimation und nicht beim Schließen von SlidingMenu
Michał K

Keine der Korrekturen hat bei mir funktioniert. Ich habe praktisch das gleiche Problem wie Michal K. Verwenden von SlidingMenu und langsames Öffnen oder Schließen mit kontinuierlicher Geschwindigkeit, und es gibt kein Problem. Öffnen Sie das Fenster oder drücken Sie zurück, um das Fenster zu schließen. Es sieht so aus, als ob die Karte etwas zurückbleibt und ein Leerzeichen hinterlässt, bis die Folie dort endet, wo die Karte an ihre richtige Position zurückkehrt.
qubz

@qubz: Über das 'Schiebemenü' versuchen Sie, das Menü und nicht die Karte zu animieren. Es hat das Problem für mich gelöst, wenn sich die Karte nicht bewegt.
meh

@meh: Die Karte bewegt sich möglicherweise, während ich das SlidingMenu öffne / schließe. Mit Bewegen meine ich CameraUpdate. Ich werde sehen, ob ich die Animation anhalten kann, obwohl dies UX behindern wird.
Qubz

@ Lubos Horacek: Könnten Sie bitte einen Beispielcode posten.
Ich

7

Google hat ein Update dafür veröffentlicht, jedoch nur für 4.1+ (Sie müssen keine neue Version von PlayServices herunterladen, sie haben ein serverseitiges Flag verwendet).

Folgendes verwende ich, um das Problem zu umgehen: Stellt sicher, dass Sie keine CPU-Zyklen auf Geräten> = 4.1 verschwenden

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

Ich denke, Sie verweisen auf die Klasse wie folgt: FixMapFragment mapFragment = (FixMapFragment) fragmentManager.findFragmentById(R.id.map);und in der Layoutdatei : <fragment android:id="@+id/map" android:name="com.example.fragments.FixMapFragment" .... Soweit ich das beurteilen kann, flackert die Karte immer noch (Android 4.0.4).
JJD

@JJD Ich habe eine Kartenansicht, die flackert. Gibt es eine Möglichkeit, das zu lösen?
Rat-a-tat-a-tat Ratatouille

@ Rat-a-tat-a-tatRatatouille Soweit ich weiß, gibt es keine zuverlässige Problemumgehung, um das Flackern der Kartenansicht zu vermeiden.
JJD

Ich weiß nicht, ob das, was ich jetzt getan habe, richtig ist oder nicht, aber es funktioniert. Ich habe die Sichtbarkeit der Kartenansichten auf unsichtbar gesetzt und nach einigen Sekunden die Sichtbarkeit der Kartenansichten wieder auf sichtbar gesetzt. reduziert das Flimmern.
Rat-a-tat-a-tat Ratatouille

6

Meine Problemumgehung: Verwenden Sie die neue Snapshot-Oberfläche von GoogleMap und zeigen Sie beim Scrollen der Seite einen Snapshot der Karte an.

Hier ist mein Code zum Festlegen des Snapshots (er befindet sich im selben Fragment wie map, 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;
    }
}

Wobei "mapFragment" mein SupportedMapFragment und "iv" eine ImageView ist (machen Sie es match_parent).

Und hier steuere ich die Schriftrolle:

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

Mein Fragment mit Karte (FragmentMap) befindet sich auf Position 1, daher muss ich den Bildlauf von Position 0 nach 1 und von Position 1 nach 2 steuern (die erste if-Klausel). "getRegisteredFragment ()" ist eine Funktion in meinem benutzerdefinierten FragmentPagerAdapter, in dem ich ein SparseArray (Fragment) namens "registerFragments" habe.

Wenn Sie also zu oder von Ihrer Karte scrollen, sehen Sie immer eine Momentaufnahme davon. Das funktioniert sehr gut für mich.


Die anderen Antworten haben bei mir nicht funktioniert - dies ist die einzige, die funktioniert hat. Vielen Dank!
Alice_Silver_man

4

Ich hatte dasselbe Problem von schwarzem Bildschirm auf der Listenansicht Scrollen, i Karte Fragment wurde mit mit Listenansicht im gleichen Bildschirm i mit der Nutzung dieses Problem gelöst habe von der magischen Eigenschaft in xml , wo ich Liste Ansicht spreche nur wir setzen haben android: scrollingCache = "false". Mein Problem ist behoben. Versuchen Sie diese Eigenschaft, um Verzögerungen und Flackern in Ihren Karten zu vermeiden.


2

Sie haben nicht viele Details angegeben, daher kann ich nur so viel vorschlagen. Ich hatte ein ähnliches Problem, bei dem der Bildschirm zwischen den Ansichten im Pager flackerte. Es stellte sich heraus, dass die MapView beim ersten Wechseln zwischen Seiten aufgeblasen wurde.

Um klar zu sein, ich hatte 3 Seiten in meinem Pager und meine Karte war die letzte Seite.

Um dies zu lösen, stellte ich fest, dass beim Setzen der Anzahl der Off-Screen-Seiten auf 2 (dies funktionierte im obigen Fall) alle Ansichten auf einmal geladen wurden, als mein Fragment gestartet wurde.

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


Danke, aber nicht funktioniert. Das Problem ist, dass der von der Karte abgedeckte Teil des Bildschirms beim Wechsel zu einem anderen Fragment schwarz bleibt und die Ansicht dieses anderen Fragments abdeckt.
Pepe

hmmm interessant. Ich werde darüber nachdenken.
Graham Smith

Ich kann setOffscreenPageLimit auf dieser Seite nicht finden, die mit
mplungjan

0

Es gibt noch eine Lösung für dieses Problem. Ich zeige MapFragment in einem anderen Fragment. Das MapFragment wird dynamisch zum FrameLayout hinzugefügt.

Die Lösung besteht darin, frameLayout.setVisibility (View.Visible) und frameLayout.setVisibility (View.Gone) zum Öffnen und Schließen von Ereignissen des Schiebemenüs zu verwenden. Es muss eine zusätzliche Ansicht hinzugefügt werden. Und der schwarze Bereich ist komplett verschwunden.

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

getSlidingMenu().setOnClosedListener(
        new OnClosedListener() {

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

0

Keine der oben genannten Methoden hat bei mir funktioniert, nicht einmal andere, die ich anderswo gefunden habe. Schließlich habe ich eine Teillösung gewählt. Ich höre Seitenänderungen über den onPageChangeListener des ViewPagers ab und verstecke die Karte, wenn die Seite zu scrollen beginnt, und zeige sie ebenfalls wieder an, wenn sie nicht mehr scrollt. Ich habe auch eine weiße Ansicht hinzugefügt, die beim Scrollen angezeigt wird.


Es kann weiter erweitert werden, um das aktuelle Bild der Ansicht in einer Bitmap zu erfassen und es dann in einer ImageView anzuzeigen, während der Pager einen Bildlauf durchführt. Auf diese Weise würden Benutzer den Hack dahinter nicht bemerken. Ich fand diese Berechnung jedoch etwas zu teuer, da sie die Reaktion der Benutzeroberfläche auf das Wischen verlangsamen würde.
Azyoot

-2

Kopieren Sie einfach mein benutzerdefiniertes Kartenfragment in Ihr Projekt. Und wenn Sie schwarze Linien mit ScrollView oben und unten auf Ihrem ScrollView-Android haben: 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();
}

}}

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.