J'essaie d'implémenter une nouvelle Android API Google Maps (v2). Cependant, cela ne semble pas bien aller avec SlidingMen . Comme vous le savez peut-être, MapFragment
est basée sur SurfaceView
. Le problème est que SurfaceView
n'aime pas le déplacer - je veux dire le placer dans des vues mobiles:
ViewPager
,ScrollView
,ListView
,SlidingMenu
susmentionné.Lorsque vous le déplacez, il laisse un trou noir à l'endroit où se trouvaient initialement ses pixels. Cela ressemble à this .
Ce problème peut être partiellement résolu en spécifiant un arrière-plan transparent sur le SurfaceView
ou même en plaçant un View
transparent dessus. Je n'arrive pas à comprendre si ce n'est que pour moi que les résultats sont inacceptables, ou si j'ai un problème différent qui le fait ressembler.
Pour voir à quoi cela ressemble, veuillez regarder CETTE VIDÉO .
(désolé pour la qualité, mais le problème peut être vu de toute façon facilement)
Lorsqu'une vue de liste normale (l'écran orange) est retirée lors de l'ouverture de SlidingMenu
, l'animation est fluide et agréable. Mais dès que MapFragment
apparaît, il y a un problème bizarre de rafraîchissement/scintillement/synchronisation 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 démarre, prenez une capture d'écran du Prendre une capture d'écran d'une carte n'est pas possible , mais peut-être que quelqu'un s'en inspirera.MapFragment
(cela devrait être possible avec SurfaceView) et déposez-la pendant la durée de l'animation. Mais je ne sais vraiment pas comment faire ...
Ou peut-être désactiver le redessinage de la carte d'une autre manière, je ne sais pas.
MISE À JOUR:
Trouvé ce .
Il semble que SurfaceView puisse être remplacé par TextureView pour supprimer ces limitations. Mais puisque MapFragment est basé sur SurfaceView, je ne sais pas si cela peut être réalisé.
Une autre mise à jour Il semble que ce problème a été résolu sur les appareils 4.1+. Ils ont juste utilisé TextureView. mais sur les versions inférieures, nous devons encore utiliser des solutions de contournement.
Bien sûr, la solution appropriée consistera pour Google à résoudre le problème (voir Android Maps V2 issue 4639: http://code.google.com/p/gmaps-api- issues/issues/detail? id = 4639 ).
Cependant, l'un de mes collègues a suggéré d'étendre simplement 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 ceci:
Android:layout_marginLeft="-40dp"
Android:layout_marginRight="-40dp"
nous pouvons réduire/éliminer le scintillement. Les appareils plus récents (par exemple Galaxy Nexus) ne montrent aucun 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 afin que les fenêtres d'informations soient centrées quand ils sont sélectionnés.
Mise à jour: ce problème a été résolu par Google le 28 août, mais je suppose qu'il doit encore être intégré dans une version.
Vous pouvez utiliser cette bibliothèque
https://github.com/NyxDigital/NiceSupportMapFragment/
cela fonctionne bien pour moi.
Voici une idée folle, ne déplacez pas le MapView ;-)
Autrement dit, créez une largeur de plein écran MapView derrière votre application dans un FrameLayout. Ensuite, posez vos vues sur le dessus et percez un trou dans MapView dans la position dont vous avez besoin pour l'afficher. Lors du déplacement, vous devrez mettre à jour la position de la carte pour rester synchronisé afin que l'utilisateur continue de voir la même section de la carte, mais cela devrait être mieux mis à jour que de déplacer une vue de surface.
Eh bien, citant Dianne Hackborn (un Android)
La vue de la surface est en fait DERRIÈRE votre fenêtre et un trou percé dans la fenêtre pour que vous puissiez le voir. Vous pouvez donc mettre des objets dessus dans votre fenêtre, mais rien dans votre fenêtre ne peut apparaître derrière. Message d'origine
Cette architecture fait partie des raisons pour lesquelles vous voyez ces scintillements.
Certains scintillements apparaissent parfois en raison de doubles tampons: le blog de codage Android explique plus en détail .
Vous pouvez également essayer de sous-classer le SurfaceView
pour essayer de dessiner l'arrière-plan différemment. Je n'ai pas vu un exemple de cela qui ne change pas le z-index pour être celui du sommet. Découvrez ce SO post
Sinon, je recommande de n'obtenir le SurfaceHolder
qu'après que votre vue est focalisée (essayez de faire une vue temporaire jusque-là) et de supprimer le SurfaceView
sans être au point et à l'écran.
Prendre une capture d'écran d'une carte n'est pas possible, mais peut-être que quelqu'un s'en inspirera.
C'est possible avec interface snapshot de GoogleMap . Vous pouvez maintenant afficher un instantané de la carte tout en faisant défiler la page. Avec cela, j'ai résolu mon problème avec le ViewPager, vous pouvez peut-être changer le code pour l'adapter à votre SlidingMenu.
Voici mon code pour définir l'instantané (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 SupportedMapFragment et "iv" est un ImageView (faites-le match_parent).
Et ici, je contrôle le défilement:
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 carte (FragmentMap) est en position 1, j'ai donc besoin de contrôler le défilement de la position 0 à 1 et de la position 1 à 2 (la première clause if). "getRegisteredFragment ()" est une fonction de mon FragmentPagerAdapter personnalisé, dans laquelle j'ai un SparseArray (Fragment) appelé "registeredFragments".
Ainsi, chaque fois que vous faites défiler vers ou depuis votre carte, vous en voyez toujours un instantané. Cela fonctionne très bien pour moi.
Une autre solution alternative consiste à utiliser la nouvelle fonction GoogleMap.snapshot()
et à utiliser une capture d'écran de la carte à la place; comme décrit ici .
Dans mon scénario, j'avais un fragment initial, qui sur un clic de bouton échangeait un deuxième fragment avec un MapFragment à l'intérieur. J'ai remarqué que ce scintillement ne se produisait que la première fois que vous échangiez le fragment - en éclatant la pile arrière, et en échangeant un autre fragment du même type ne provoquait pas de scintillement.
Donc, pensant que cela avait quelque chose à voir avec l'ajout d'une SurfaceView initiale à la fenêtre, j'ai essayé d'ajouter une instance vide d'une SurfaceView à mon fragment initialement chargé, derrière sa vue principale. Et bingo, plus de scintillement lors de l'animation dans le prochain fragment!
Je sais que ce n'est pas la solution la plus propre, mais cela fonctionne. Le Google MapFragment (ou SupportMapFragment dans mon cas) fonctionne toujours bien, car le SurfaceView inutilisé se trouve dans le fragment précédent.
Je dois ajouter que j'utilise l'API v2.
Mise à jour @VenomVendor
J'ajoute la SurfaceView vide au premier fragment à afficher, à l'index 0 - derrière la vue principale. Dans mon cas, le fragment Home est le fragment précédent à celui qui contient le fragment Google Maps, je ne sais pas 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);
...
}
ajouter Android:hardwareAccelerated="true"
dans votre fichier manifeste.
par exemple: <application Android:name=".Sample" Android:hardwareAccelerated="true" />
J'ai eu le même problème avec une vue Web et SlidingMenu et j'ai résolu en modifiant le code source de SlidingMenu comme expliqué ici par le développeur principal.
Commentez l'accélération matérielle dans la méthode manageLayers de SlidingMenu. Cela semble être la seule solution car SurfaceViews ne fonctionne pas.
Pour empêcher MapView (il s'agit en fait d'une SurfaceView) de créer des trous noirs, j'ajoute une vue vide avec une couleur d'arrière-plan transparente pour couvrir toute la MapView, de sorte qu'elle puisse empêcher MapView de générer un "trou" noir. Cela peut fonctionner pour votre situation.
Changez votre FrameLayout en RelativeLayout si possible
J'ai eu le même problème d'écran noir lors du défilement de la vue de liste, j'utilisais un fragment de carte avec la vue de liste dans le même écran, j'ai résolu ce problème en utilisant la propriété magique en xml où je parle en vue de liste il suffit de mettre Android: scrollingCache = "false". mon problème est résolu essayez cette propriété pour arrêter le retard et le scintillement dans vos cartes.
essayez d'ajouter ..
getHolder (). setFormat (PixelFormat.TRANSLUCENT);
au constructeur de votre SurfaceView. Le TextureView devrait également fonctionner, mais vous demandera de supprimer le support pour les appareils sub api 14.
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);
Cela a fonctionné pour moi ... Ajouter la 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"
Les gars, la meilleure solution que j'ai trouvée était d'instancier votre carte de support à travers cela. Fait des merveilles
SupportMapFragment mapFragment = SupportMapFragment.newInstance(new GoogleMapOptions().zOrderOnTop(true));