ViewPager con Google Maps API v2: misteriosa vista en negro


95

He integrado el nuevo fragmento api v2 de google maps en un paginador de vistas. Al desplazarse desde el fragmento del mapa, una vista en negro se superpone a los fragmentos adyacentes. ¿Alguien lo ha resuelto?

Editar: captura de pantalla

ingrese la descripción de la imagen aquí

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

¿Ocurre en más de un dispositivo? Tal vez unas pocas líneas de código de su ViewPager y la implementación del mapa puedan ayudar a comprender mejor su problema.
Adinia

Sí, ocurre en todos los dispositivos que probé: samsung, htc, android 4.0, 2.3, etc. He integrado el mapa en mi aplicación y en una pequeña aplicación limpia con solo el localizador y el mapa, con el mismo resultado.
Pepe

@Pepe, ¿podrías decir cómo obtienes el GoogleMapobjeto del ViewPager? Atascado en esto durante semanas. Si no entendió bien la pregunta, busque mi pregunta, encontrará mi publicación. Por favor responde.
azizbekian

Quiero agregar que cuando se hace un screen recordproblema, el problema no parece suceder.
theblang

Respuestas:


115

Pude evitar que la superficie negra quedara atrás después de la transición colocando otra vista con un fondo transparente en la parte superior del ViewPagerinterior 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
¡Excelente! No es perfecto, porque a veces mientras se mueve el buscapersonas aparece parte de la vista en negro. Pero ahora ya no permanece en pantalla. ¡Gracias! (¿Tiene alguna explicación para este truco?)
Pepe

7
Realmente no. Me di cuenta de que los controles de zoom y ubicación estaban en la parte superior de la superficie del mapa, el rastro negro no aparecía, así que coloqué una vista en la parte superior para cubrir todo el mapa y funcionó. Estoy de acuerdo en que no es perfecto: el fondo negro parece ser parte de la ventana GLSurfaceView code.google.com/p/gmaps-api-issues/issues/detail?id=4639
Jeff Gilfelt

5
Parece que solucionó mi problema de ViewPager. Gracias, pero parece que tengo un problema similar con SlideMenu (menú de la izquierda como G + / Yahoo), haciendo lo mismo .. ¿Alguna idea sobre cómo arreglar una implementación de SlideMenu?
Chrispix

@Chrispix no anima el contenedor, usa la animación solo en el menú lateral, me lo arregló.
meh

1
He hecho esto y la siguiente solución programática, funcionan mientras la aplicación está en primer plano, pero cuando la aplicación está cerrada y aún se está ejecutando y vuelve a ella, el mapa permanece en la parte superior todavía ..
L7ColWinters

43

Tuve el mismo problema con SlidingMenu y ViewPager. Noté que los botones de control en el fragmento de mapa no son negros en el artefacto dejado atrás. Resolví el problema anulando el onCreateView()método deMapFragment (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;
}

También lo uso para SlidingMenu. Pero tengo el problema del parpadeo (con la animación deslizante) y es inaceptable, se ve horrible. ¿Tú también lo tienes? Probé en HTC One S. Lo que es interesante, solo tengo este problema con la animación de apertura y no al cerrar SlidingMenu
Michał K

Ninguna de las correcciones funcionó para mí. Tengo prácticamente el mismo problema que Michal K. Usando SlidingMenu y abriendo o cerrando lentamente a una velocidad continua y no hay problema. Abra o presione hacia atrás para cerrar la ventana y parece que el mapa se retrasa un poco dejando un espacio en blanco hasta que la diapositiva termina donde el mapa vuelve a su posición correcta.
qubz

@qubz: Acerca del 'menú deslizante', intente animar el menú y no el mapa. Me resolvió el problema si el mapa no se mueve.
meh

@meh: Es posible que el mapa se esté moviendo mientras abro / cierro el menú deslizante. Al mover me refiero a CameraUpdate. Veré si puedo pausar la animación, aunque esto dificultará la experiencia de usuario.
qubz

@Lubos Horacek: ¿Podrían publicar un código de muestra? Recibo un error de excepción de puntero nulo ..
avinash

7

Google lanzó una solución para esto, pero solo para 4.1+ (no necesita descargar una nueva versión de PlayServices, usaron una bandera del lado del servidor)

Esto es lo que estoy usando para evitar el problema: garantiza que no desperdicie ningún ciclo de CPU en dispositivos> = 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);
            }
        }
    }
}

Creo que se hace referencia a la clase de la siguiente manera: FixMapFragment mapFragment = (FixMapFragment) fragmentManager.findFragmentById(R.id.map);y en el archivo de diseño: <fragment android:id="@+id/map" android:name="com.example.fragments.FixMapFragment" .... Sin embargo, el mapa todavía parpadea por lo que puedo decir (Android 4.0.4).
JJD

@JJD tengo una vista de mapa que parpadea, ¿hay alguna manera de solucionarlo?
Rat-a-tat-a-tat Ratatouille

@ Rat-a-tat-a-tatRatatouille No existe una solución alternativa confiable para evitar el parpadeo de la vista del mapa que yo sepa.
JJD

No sé si lo que he hecho por ahora es correcto o no, pero funciona. Configuré la visibilidad de la vista del mapa en invisible y luego, después de unos segundos, configuré la visibilidad de la vista del mapa en visible. reduce el parpadeo.
Rat-a-tat-a-tat Ratatouille

6

Mi solución alternativa: utilice la nueva interfaz de instantáneas de GoogleMap y muestre una instantánea del mapa mientras se desplaza por la página.

Aquí está mi código para configurar la instantánea (está en el mismo fragmento que el mapa, llamado 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;
    }
}

Donde "mapFragment" es mi SupportedMapFragment y "iv" es un ImageView (hágalo match_parent).

Y aquí estoy controlando el pergamino:

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

Mi fragmento con mapa (FragmentMap) está en la posición 1, por lo que necesito controlar el desplazamiento desde la posición 0 a 1 y desde la posición 1 a 2 (la primera cláusula if). "getRegisteredFragment ()" es una función en mi FragmentPagerAdapter personalizado, en el que tengo un SparseArray (Fragmento) llamado "isteredFragments ".

Por lo tanto, cada vez que se desplaza hacia o desde su mapa, siempre ve una instantánea del mismo. Este trabajo es muy bueno para mi.


Las otras respuestas no funcionaron para mí, esta es la única que funcionó. ¡Gracias!
alice_silver_man

4

Tuve el mismo problema de pantalla negra en el desplazamiento de la vista de lista, estaba usando un fragmento de mapa con la vista de lista en la misma pantalla, resolví este problema con el uso de la propiedad mágica en xml donde estoy hablando de la vista de lista, solo tenemos que poner Android: scrollingCache = "false" .mi problema está solucionado, pruebe esta propiedad para detener el retraso y el parpadeo en sus mapas.


2

No ha dado muchos detalles, así que solo puedo sugerir algo. Tuve un problema similar en el que la pantalla parpadeaba entre las vistas del buscapersonas. Resultó que mapView se inflaba al cambiar de página por primera vez.

Para ser claros, tenía 3 páginas en mi localizador y mi mapa era la última página.

Para resolver esto, encontré que estableciendo el número de páginas fuera de la pantalla en 2 (esto funcionó en el caso anterior), cuando mi fragmento comenzó, cargó todas las vistas a la vez.

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


Gracias, pero no funcionó. El problema es que la parte de la pantalla cubierta por el mapa, cuando cambia a otro fragmento, permanece negra, cubriendo la vista de este otro fragmento.
Pepe

hmmm interesante. Pensaré en esto.
Graham Smith

No puedo encontrar setOffscreenPageLimit en esa página a la que está vinculado
mplungjan

0

Hay una solución más a este problema. Estoy mostrando MapFragment dentro de otro fragmento. MapFragment se agrega dinámicamente en un FrameLayout.

La solución es utilizar frameLayout.setVisibility (View.Visible) y frameLayout.setVisibility (View.Gone) en los eventos de apertura y cierre del menú deslizante. No requiere agregar una vista adicional. Y el área negra desapareció por completo.

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

Ninguno de los métodos anteriores funcionó para mí, ni siquiera otros que he encontrado en otros lugares. Finalmente, elegí una solución parcial. Escucho los cambios de página a través del onPageChangeListener de ViewPager, y oculto el mapa cuando su página comienza a desplazarse, y también lo muestro de nuevo cuando deja de desplazarse. También agregué una Vista en blanco para que se muestre al desplazarse.


Se puede ampliar aún más para capturar la imagen actual de la vista en un mapa de bits y luego mostrarla en una vista de imagen mientras el buscapersonas se desplaza. De esa manera, los usuarios no notarían el hackeo detrás de él. Sin embargo, este cálculo me pareció un poco caro, ya que ralentizaría la respuesta de la interfaz de usuario al deslizar.
azyoot

-2

Simplemente copie mi fragmento de mapa personalizado a su proyecto. Y si tiene líneas negras con ScrollView en la parte superior e inferior configurada para su 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();
}

}

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.