Le déplacement D'un fragment de carte (Vue de surface) provoque un scintillement de fond noir

j'essaie de mettre en œuvre une nouvelle API GoogleMaps Android (v2). Cependant, il ne semble pas aller bien avec SlidingMenu . Comme vous le savez peut-être, MapFragment est basé sur SurfaceView . Le problème est que le SurfaceView n'aime pas le déplacer - je veux dire le placer dans des vues mobiles:

quand vous le déplacez, il laisse un trou noir à l'endroit où ses pixels ont été posés à l'origine. Il ressemble à quelque chose comme ce .

ce problème peut être partiellement résolu en spécifiant un fond transparent sur le SurfaceView ou même en plaçant un transparent View sur elle. Je n'arrive pas à comprendre si seulement pour moi les résultats sont inacceptables, ou si j'ai un autre problème qui le fait paraître comment il regarde.

pour voir à quoi il ressemble, s'il vous plaît regarder cette vidéo .

(désolé pour la qualité, mais le problème peut être vu facilement de toute façon)

quand un listview normal (l'écran orange) est retiré en ouvrant SlidingMenu , l'animation est lisse et agréable. Mais dès que le MapFragment apparaît, il y a un problème de rafraîchissement/scintillement/synchronisation bizarre sur la carte.

testé sur HTC One S et Samsung Galaxy ACE.


mon idée super - folle de la résoudre: chaque fois que l'animation d'ouverture commence, prenez une capture d'écran du MapFragment (cela devrait être possible avec SurfaceView) et mettez-la en place pour la durée de l'animation. Mais Je ne sais vraiment pas comment le faire... prendre la capture d'écran d'une carte n'est pas possible , mais peut-être que quelqu'un s'en inspirera.

ou peut-être désactiver redessiner la carte d'une autre façon, je ne sais pas.


mise à jour:

Trouvé ce .

il semble que SurfaceView peut être changé en TextureView pour supprimer ces restrictions. Mais puisque MapFragment est basé sur SurfaceView, Je ne sais pas si cela peut être réalisé.

une autre mise à jour Il semble que cette question ait été résolue pour les dispositifs 4.1+. Ils ont utilisé TextureView. mais sur les versions plus basses, nous devons toujours utiliser des solutions de contournement.

53
demandé sur Community 2013-01-20 02:24:13

17 réponses

bien sûr, la bonne solution sera pour Google à corriger le problème (Voir Android Maps v2 numéro 4639: http://code.google.com/p/gmaps-api-issues/issues/detail?id=4639 ).

cependant, un de mes collègues a suggéré simplement d'étendre la carte au-delà de son conteneur. Si nous étendons le fragment de carte au-delà de la région visible de son conteneur, comme ainsi:

android:layout_marginLeft="-40dp"
android:layout_marginRight="-40dp"

nous pouvons réduire/éliminer le scintillement. Nouveau les appareils (par exemple Galaxy Nexus) ne montrent pas de scintillement après ce piratage, et les appareils plus anciens (par exemple LG Optimus V) montrent un scintillement réduit. Nous devons étendre les marges des deux côtés pour que les fenêtres d'information soient centrées quand elles sont sélectionnées.


mise à jour: 28, mais je suppose qu'il doit encore être roulé dans une décharge.

14
répondu Daniel Schuler 2013-08-28 12:17:14

vous pouvez utiliser cette bibliothèque

https://github.com/NyxDigital/NiceSupportMapFragment /

ça me va très bien.

6
répondu Erick Martinez 2013-10-15 21:14:44

Voici une idée folle, ne pas déplacer la MapView ;-)

c'est-à-dire, créer un MapView plein écran largeur derrière votre application dans un FrameLayout. Ensuite, placez vos vues sur le dessus et percez un trou dans le MapView dans la position où vous devez l'afficher. Lorsque vous déménagez, vous devez mettre à jour la position de la carte pour rester dans la synchronisation de sorte que l'Utilisateur continue de voir la même section de la carte, mais qui devrait mettre à jour mieux que de déplacer une vue de surface autour.

4
répondu Ryan 2013-01-21 23:05:00

puits, Citant Dianne Hackborn (un Androïde cadre de l'ingénieur)

la vue de surface est en fait derrière votre fenêtre, et un trou percé dans la fenêtre pour vous de le voir. Vous pouvez mettre les choses sur le dessus de votre fenêtre, mais rien dans votre fenêtre peut apparaître derrière elle. post Original

cette architecture fait partie des raisons pour lesquelles vous voyez ces clignotants.

Some des clignotements apparaissent parfois en raison de doubles tampons: Android code blog explique plus .

vous pouvez également essayer et sous-classe le SurfaceView pour essayer de dessiner le fond différemment. Je n'ai pas vu un exemple de cela qui ne change pas le z-index pour être celui du haut. découvrez ce DONC, après les

sinon, je recommande d'obtenir seulement le SurfaceHolder après que votre vue est concentrée (essayer et faire un le SurfaceView n'est pas visible à l'écran.

3
répondu Ben Max Rubinstein 2017-05-23 12:34:51

Prendre des capture d'écran d'une carte n'est pas possible, mais peut-être que quelqu'un aura inspiré.

C'est possible avec l'interface snapshot de GoogleMap . Vous pouvez maintenant afficher un instantané de la carte en faisant défiler la page. Avec ceci j'ai résolu mon problème avec le ViewPager, peut-être que vous pouvez changer le code pour s'adapter à votre SlidingMenu.

Voici mon code pour configurer le snapshot (il est dans le même fragment que la carte, appelé 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;
    }
}

où " mapFragment "est mon Supportmapfragment et" iv " est une ImageView (make it match_parent).

et ici je contrôle le rouleau:

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

mon fragment avec map (FragmentMap) est en position 1, donc je dois contrôler le rouleau de la position 0 à 1 et de la position 1 à 2 (la première clause if). "getRegisteredFragment()" est une fonction dans mon custom FragmentPagerAdapter, dans lequel j'ai un SparseArray (Fragment) appelé "registeredFragments".

Donc, chaque fois que vous faites défiler jusqu'à ou à partir de votre carte, vous voyez toujours un instantané. Cela fonctionne très bien pour moi.

2
répondu Namenlos 2013-08-14 11:26:04

pour empêcher la création des trous noirs par le MapView(il S'agit en fait d'un SurfaceView), j'ajoute une vue vide avec une couleur de fond transparente pour couvrir l'ensemble du MapView, de sorte qu'il puisse empêcher le MapView de générer un"trou" noir. Ça peut marcher pour votre situation.

1
répondu Acheese 2013-03-07 06:37:12

j'ai eu le même problème avec un webview et SlidingMenu et j'ai résolu en modifiant le code source de SlidingMenu comme expliqué ici par le développeur principal.

commente l'accélération matérielle dans la méthode manageLayers de SlidingMenu. Cela semble être la seule solution depuis SurfaceViews ne fonctionne pas.

1
répondu sourcerebels 2013-07-04 12:27:08

une autre solution est d'utiliser la nouvelle fonction GoogleMap.snapshot() , et d'utiliser une capture d'écran de la carte à la place; comme décrit ici .

1
répondu joecks 2017-05-23 12:34:51

dans mon scénario, j'ai eu un Fragment initial, qui sur un clic de bouton a changé dans un second fragment avec un fragment de carte à l'intérieur. J'ai remarqué que ce clignotement ne se produisait que la première fois que vous changiez le fragment - sautant la pile arrière, et l'échange dans un autre fragment du même type n'a pas causé un clignotement.

donc en se disant que cela avait quelque chose à voir avec l'ajout d'une vue de surface initiale à la fenêtre, j'ai essayé d'ajouter une instance vide D'une vue de surface à mon fragment chargé au départ, derrière la vue principale. Et bingo, plus de scintillement lors de l'animation dans le fragment suivant!

je sais que ce n'est pas la solution la plus propre, mais ça marche. Le Google MapFragment (ou SupportMapFragment dans mon cas) fonctionne toujours bien, comme le SurfaceView non utilisé est dans le fragment précédent.

j'ajoute que j'utilise l'API v2.

Mise À Jour @VenomVendor

j'ajoute la vue de surface vide du premier fragment à afficher, à l'index 0-derrière la vue principale. Dans mon cas, le fragment Home est le fragment précédent d'un fragment qui contient le fragment Google Maps, pas sûr si cela importe:

import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class HomeFragment extends FragmentBase {
private SurfaceView sview;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_home, container, false);

    //this fixes google maps surface view black screen animation issue
    sview = new SurfaceView(getActivity());
    sview.setZOrderOnTop(true);    // necessary
    SurfaceHolder holder = sview.getHolder();
    holder.setFormat(PixelFormat.TRANSPARENT);

    container.addView(sview, 0);
    ...
}
1
répondu Breeno 2014-03-28 09:01:14

j'ai eu le même problème d'écran noir sur le défilement de la vue de liste, j'ai utilisé fragment de carte avec la vue de liste dans le même écran j'ai résolu ce problème avec l'utilisation de la propriété magique en xml où je parle vue de liste juste nous devons mettre android:scrollingCache=" false " .mon problème est corrigé essayez cette propriété pour arrêter le retard et le scintillement dans vos cartes.

0
répondu Priyank Bhojak 2013-04-22 09:54:32

les gars, la meilleure solution que j'ai trouvée était d'instancier votre carte de soutien à travers ceci. Fait des merveilles

SupportMapFragment mapFragment = SupportMapFragment.newInstance(new GoogleMapOptions().zOrderOnTop(true));
0
répondu SoH 2014-02-21 13:20:25

essayez d'ajouter..

getHolder().setFormat (PixelFormat.Translucide);

au constructeur de votre SurfaceView. La version TextureView devrait aussi fonctionner, mais vous devrez supprimer le support pour les périphériques sub api 14.

0
répondu Lee 2014-06-24 11:09:55

changez votre FrameLayout en RelativeLayout si Possible

0
répondu Reza 2014-11-09 20:26:15

j'ai eu le même problème et j'ai utilisé une solution de contournement basée sur la modification de la"visibilité".

private GoogleMap mMap;
private SupportMapFragment mMapFragment;

mMapFragment = ((SupportMapFragment)getSupportFragmentManager().findFragmentById(R.id.mapFragment));
mMap = mMapFragment.getMap();

//Change the visibility to 'INVISIBLE' before the animation to go to another fragment.
mMapFragment.getView().setVisibility(View.INVISIBLE);

//Change the visibility to 'VISIBLE' after coming back to the original fragment that has map fragment.
mMapFragment.getView().setVisibility(View.VISIBLE);
0
répondu kalan 2014-12-04 04:13:15

ça a marché pour moi... Ajouter carte: zOrderOnTop= "true" à votre fragment comme ceci...

<fragment
                android:id="@+id/map"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:name="com.google.android.gms.maps.SupportMapFragment""
                map:zOrderOnTop="true"/>

N'oubliez pas d'ajouter ceci à votre ScrollView parent

xmlns:map="http://schemas.android.com/apk/res-auto"
0
répondu karenms 2016-12-22 21:11:59

ajouter android:hardwareAccelerated="true" dans votre fichier manifeste.

par exemple: <application android:name=".Sample" android:hardwareAccelerated="true" />

0
répondu Nagalakshmi 2018-05-16 10:23:05

voici un contournement très simple que j'ai utilisé pour me débarrasser du clignotement dans un ViewPager. J'imagine qu'il en sera de même pour N'importe quel Fragment ou autre MapView ajouté dynamiquement.

le problème ne semble pas être la MapView elle-même, mais les ressources nécessaires pour exécuter la MapView. Ces ressources ne sont chargées que la première fois que vous activez un MapView dans votre activité et réutilisées pour chaque MapView suivant, comme vous vous y attendiez. Cette charge de ressources est quelles sont les causes d'un flash à l'écran.

donc pour enlever le clignotement, j'ai juste inclus un autre MapView dans la disposition de mon activité (l'emplacement dans l'activité n'est pas pertinent). Dès que L'activité est chargée, je règle la visibilité de MapView supplémentaire à GONE. Cela signifie que toutes les ressources nécessaires pour votre MapView sont prêtes pour quand vous allumez l'un de vos Fragments en utilisant MapViews sans retard, sans clignotement, tout le bonheur.

c'est bien sûr un solution et pas une vraie "solution" au problème sous-jacent, mais il permettra de résoudre les effets secondaires.

Afin de couvrir le code utilisé pour l'exhaustivité:

placé de façon aléatoire (mais propre) dans la disposition de mon activité:

<com.google.android.gms.maps.MapView
        android:id="@+id/flash_map"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

puis dans ma classe D'activité

private MapView flashMap;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

            // Code omitted

    try {
        MapsInitializer.initialize(this);
    } catch (GooglePlayServicesNotAvailableException e) {
        e.printStackTrace();
    }
    flashMap = (MapView)findViewById(R.id.flash_map);
    flashMap.onCreate(savedInstanceState);
}

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
        flashMap.onSaveInstanceState(outState);
}

@Override
public void onResume() {
    super.onResume();
    flashMap.onResume();
    flashMap.setVisibility(View.GONE); // Just like it was never there...
}

@Override
public void onPause() {
    flashMap.onPause();
    super.onPause();
}

@Override
public void onDestroy() {
    flashMap.onDestroy();
    super.onDestroy();
}

@Override
public void onLowMemory() {
    super.onLowMemory();
    flashMap.onLowMemory();
}
-1
répondu Scott 2013-01-30 04:42:48