ViewPager con API di Google Maps v2: misteriosa vista nera


95

Ho integrato il nuovo frammento di google maps api v2 in un view pager. Quando si scorre dal frammento di mappa, una vista nera si sovrappone ai frammenti adiacenti. Qualcuno ha risolto?

Modifica: screenshot

inserisci qui la descrizione dell'immagine

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

Succede su più di un dispositivo? Forse alcune righe di codice da te ViewPager e l'implementazione della mappa potrebbero aiutare a comprendere meglio il tuo problema.
Adinia

Sì, succede su tutti i dispositivi che ho provato: samsung, htc, android 4.0, 2.3, ecc. Ho integrato la mappa nella mia app, e in una piccola app pulita con solo il cercapersone e la mappa, con lo stesso risultato.
Pepe

@ Pepe, potresti per favore dire, come si ottiene l' GoogleMapoggetto dal ViewPager? Bloccato su questo per settimane. Se non hai capito bene la domanda, cerca la mia domanda, troverai il mio post. Per favore rispondi.
azizbekian

Voglio aggiungere che quando si fa un screen recordil problema non sembra accadere.
theblang

Risposte:


115

Sono stato in grado di impedire che la superficie nera rimanga indietro dopo la transizione posizionando un'altra vista con uno sfondo trasparente sopra l' ViewPagerinterno 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
Grande! Non è perfetto, perché a volte mentre si sposta il cercapersone appare parte della vista nera. Ma ora non rimane più sullo schermo. Grazie! (hai qualche spiegazione per questo hack?)
Pepe

7
Non proprio. Ho appena notato dove i controlli di zoom e posizione si trovavano sulla superficie della mappa, la traccia nera non appariva, quindi ho posizionato una vista in alto per coprire l'intera mappa e ha funzionato. Sono d'accordo che non è perfetto - lo sfondo nero sembra far parte della finestra GLSurfaceView code.google.com/p/gmaps-api-issues/issues/detail?id=4639
Jeff Gilfelt

5
Sembra che abbia risolto il mio problema con ViewPager. Grazie, ma sembra che ho un problema simile con SlideMenu (menu a sinistra come G + / Yahoo), facendo la stessa cosa .. Qualche idea su come correggere un'implementazione di SlideMenu?
Chrispix

@Chrispix non anima il contenitore, usa l'animazione solo nel menu laterale, l'ha risolto per me.
meh

1
Ho fatto questo e la soluzione programmatica di seguito, funzionano mentre l'app è in primo piano ma quando l'app è chiusa e ancora in esecuzione e torni ad essa la mappa rimane ancora in alto ..
L7ColWinters

43

Ha avuto lo stesso problema con SlidingMenu e ViewPager. Ho notato che i pulsanti di controllo nel frammento di mappa non sono neri nell'artefatto a sinistra. Ho risolto il problema ignorando il onCreateView()metodo diMapFragment (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;
}

Lo uso anche per SlidingMenu. Ma ho il problema dello sfarfallio (con l'animazione scorrevole) ed è inaccettabile, sembra orribile. Ce l'hai anche tu? Ho provato su HTC One S. Ciò che è interessante, ho questo problema solo con l'animazione di apertura e non quando si chiude SlidingMenu
Michał K

Nessuna delle soluzioni ha funzionato per me. Ho praticamente lo stesso problema di Michal K. Utilizzando SlidingMenu e aprendo o chiudendo lentamente a una velocità continua e non ci sono problemi. Apri o premi Indietro per chiudere la finestra e sembra che la mappa ritardi un po 'lasciando uno spazio vuoto fino a quando la diapositiva non finisce dove la mappa ritorna nella sua posizione corretta.
qubz

@qubz: Riguardo al "menu scorrevole", prova ad animare il menu e non la mappa. Ha risolto il problema per me, se la mappa non si muove.
meh

@meh: la mappa potrebbe essere in movimento mentre apro / chiudo SlidingMenu. Per spostamento intendo CameraUpdate. Vedrò se riesco a mettere in pausa l'animazione, anche se questo ostacolerà l'UX.
qubz

@Lubos Horacek: Potresti per favore pubblicare un codice di esempio. Ricevo un errore di eccezione del puntatore nullo ..
avinash

7

Google ha rilasciato una correzione per questo, ma solo per 4.1+ (non è necessario scaricare una nuova versione di PlayServices, hanno utilizzato un flag lato server)

Ecco cosa sto usando per aggirare il problema: assicura di non sprecare cicli della CPU su dispositivi> = 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);
            }
        }
    }
}

Credo che si fa riferimento alla classe come segue: FixMapFragment mapFragment = (FixMapFragment) fragmentManager.findFragmentById(R.id.map);e nel file di layout: <fragment android:id="@+id/map" android:name="com.example.fragments.FixMapFragment" .... Tuttavia, per quanto posso dire, la mappa continua a tremolare (Android 4.0.4).
JJD

@JJD ho una visualizzazione mappa che sfarfalla, c'è un modo per risolverlo?
Rat-a-tat-a-tat Ratatouille

@ Rat-a-tat-a-tatRatatouille Non esiste una soluzione alternativa affidabile per evitare lo sfarfallio della visualizzazione della mappa per quanto ne so.
JJD

non so se quello che ho fatto per ora sia corretto o meno ma funziona. ho impostato la visibilità di mapview su invisibile e quindi, dopo alcuni secondi, ho ripristinato la visibilità di mapview su visibile. riduce lo sfarfallio.
Rat-a-tat-a-tat Ratatouille

6

La mia soluzione alternativa: utilizza la nuova interfaccia snapshot di GoogleMap e visualizza un'istantanea della mappa mentre scorri la pagina.

Ecco il mio codice per impostare lo snapshot (è nello stesso frammento di map, chiamato 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;
    }
}

Dove "mapFragment" è il mio SupportedMapFragment e "iv" è un ImageView (rendilo match_parent).

E qui sto controllando la pergamena:

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

Il mio frammento con mappa (FragmentMap) è in posizione 1, quindi devo controllare lo scorrimento dalla posizione 0 alla 1 e dalla posizione 1 alla 2 (la prima clausola if). "getRegisteredFragment ()" è una funzione nel mio FragmentPagerAdapter personalizzato, in cui ho uno SparseArray (Fragment) chiamato "registeredFragments".

Quindi, ogni volta che scorri verso o dalla tua mappa, ne visualizzi sempre un'istantanea. Questo funziona molto bene per me.


Le altre risposte non hanno funzionato per me: questa è l'unica che ha funzionato. Grazie!
alice_silver_man

4

Ho avuto lo stesso problema della schermata nera durante lo scorrimento della visualizzazione elenco, stavo usando il frammento di mappa con visualizzazione elenco nella stessa schermata ho risolto questo problema con l'uso della proprietà magica in xml dove sto parlando visualizzazione elenco, dobbiamo solo mettere Android: scrollingCache = "false". Il mio problema è stato risolto prova questa proprietà per fermare il ritardo e lo sfarfallio nelle tue mappe.


2

Non hai fornito molti dettagli, quindi posso suggerire solo così tanto. Ho avuto un problema simile a causa dello sfarfallio dello schermo tra le visualizzazioni nel cercapersone. Si è rivelato essere il mapView che si gonfia quando si passa da una pagina all'altra per la prima volta.

Per essere chiari avevo 3 pagine nel mio cercapersone e la mia mappa era l'ultima pagina.

Per risolvere questo problema ho scoperto che impostando il numero di pagine fuori schermo su 2 (questo ha funzionato nel caso sopra) che quando il mio frammento è stato avviato caricava tutte le visualizzazioni contemporaneamente.

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


Grazie, ma non ha funzionato. Il problema è che la parte dello schermo coperta dalla mappa, quando passa ad un altro frammento, rimane nera, coprendo la vista di quest'altro frammento.
Pepe

hmmm interessante. Ci penserò su.
Graham Smith

Non riesco a trovare setOffscreenPageLimit su quella pagina a cui
sei

0

C'è un'altra soluzione a questo problema. Sto mostrando MapFragment all'interno di un altro frammento. MapFragment viene aggiunto dinamicamente a FrameLayout.

La soluzione è usare frameLayout.setVisibility (View.Visible) e frameLayout.setVisibility (View.Gone) sugli eventi di apertura e chiusura del menu scorrevole. È necessario aggiungere una vista extra. E l'area nera è completamente scomparsa.

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

Nessuno dei metodi sopra ha funzionato per me, nemmeno altri che ho trovato altrove. Infine, ho scelto una soluzione parziale. Ascolto i cambiamenti di pagina tramite onPageChangeListener di ViewPager e nascondo la mappa quando la sua pagina inizia a scorrere, e allo stesso modo la mostro di nuovo quando smette di scorrere. Ho anche aggiunto una vista bianca da visualizzare durante lo scorrimento.


Può essere ulteriormente esteso per acquisire l'immagine corrente della vista in una bitmap e quindi visualizzarla su un ImageView mentre il cercapersone scorre. In questo modo, gli utenti non noterebbero l'hack dietro di esso. Tuttavia, ho trovato questo calcolo un po 'troppo costoso in quanto rallenterebbe la risposta dell'interfaccia utente allo scorrimento.
azyoot

-2

Copia semplicemente il mio frammento di mappa personalizzato nel tuo progetto. E se hai linee nere con ScrollView in alto e in basso impostato sul tuo Android ScrollView: 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();
}

}

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.