web-dev-qa-db-fra.com

MapFragment dans ScrollView

J'ai l'un des nouveaux MapFragment s dans un ScrollView. En fait, c'est un SupportMapFragment, mais de toute façon. Cela fonctionne, mais il y a deux problèmes:

  1. Lorsqu'il défile, il laisse un masque noir derrière. Le noir couvre exactement la zone où se trouvait la carte, à l'exception d'un trou où se trouvaient les boutons de zoom +/-. Voir capture d'écran ci-dessous. C'est sur Android 4.0.

  2. La vue n'utilise pas requestDisallowInterceptTouchEvent() lorsque l'utilisateur interagit avec la carte pour empêcher les touches d'interception de ScrollView, donc si vous essayez de vous déplacer verticalement dans la carte, elle fait simplement défiler le contenant ScrollView. Je pourrais théoriquement dériver une classe de vue MapView et ajouter cette fonctionnalité, mais comment puis-je demander à MapFragment d'utiliser mon MapView personnalisé au lieu de celui standard?

Partial screenshot of scrolling issue

52
Timmmm

L'application d'une image transparente sur le fragment mapview semble résoudre le problème. Ce n'est pas le plus joli, mais ça semble marcher. Voici un extrait XML qui montre ceci:

<RelativeLayout
        Android:id="@+id/relativeLayout1"
        Android:layout_width="match_parent"
        Android:layout_height="300dp" >

        <fragment
            Android:id="@+id/map"
            Android:name="com.google.Android.gms.maps.MapFragment"
            Android:layout_width="fill_parent"
            Android:layout_height="fill_parent"/>

        <ImageView
            Android:id="@+id/imageView123"
            Android:layout_width="match_parent"
            Android:layout_height="match_parent"
            Android:src="@drawable/temp_transparent" />         
</RelativeLayout>
52
walnut_head

Pour moi, l'ajout d'une ImageView transparente n'a pas aidé à supprimer complètement le masque noir. Les parties supérieure et inférieure de la carte montraient toujours le masque noir lors du défilement.

Donc, la solution, j'ai trouvé dans cette réponse avec un petit changement. J'ai ajouté,

Android:layout_marginTop="-100dp"
Android:layout_marginBottom="-100dp"

à mon fragment de carte car il était scrollview vertical. Donc, ma disposition ressemblait maintenant à ceci:

<RelativeLayout
    Android:id="@+id/map_layout"
    Android:layout_width="match_parent"
    Android:layout_height="300dp">

    <fragment
        Android:id="@+id/mapview"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        Android:layout_marginTop="-100dp"
        Android:layout_marginBottom="-100dp"
        Android:name="com.google.Android.gms.maps.MapFragment"/>

    <ImageView
        Android:id="@+id/transparent_image"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        Android:src="@color/transparent" />

</RelativeLayout>   

Pour résoudre la deuxième partie de la question, j'ai défini requestDisallowInterceptTouchEvent(true) pour mon ScrollView principal. Lorsque l'utilisateur a touché l'image transparente et s'est déplacé, j'ai désactivé le toucher sur l'image transparente pour MotionEvent.ACTION_DOWN Et MotionEvent.ACTION_MOVE Afin que le fragment de carte puisse prendre des événements tactiles.

ScrollView mainScrollView = (ScrollView) findViewById(R.id.main_scrollview);
ImageView transparentImageView = (ImageView) findViewById(R.id.transparent_image);

transparentImageView.setOnTouchListener(new View.OnTouchListener() {

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        int action = event.getAction();
        switch (action) {
           case MotionEvent.ACTION_DOWN:
                // Disallow ScrollView to intercept touch events.
                mainScrollView.requestDisallowInterceptTouchEvent(true);
                // Disable touch on transparent view
                return false;

           case MotionEvent.ACTION_UP:
                // Allow ScrollView to intercept touch events.
                mainScrollView.requestDisallowInterceptTouchEvent(false);
                return true;

           case MotionEvent.ACTION_MOVE:
                mainScrollView.requestDisallowInterceptTouchEvent(true);
                return false;

           default: 
                return true;
        }   
    }
});

Cela a fonctionné pour moi. J'espère que cela vous aide ..

35
Laksh

Cela a probablement ses racines au même endroit et provoque le problème dans cette question . La solution consiste à utiliser un cadre transparent, qui est un peu plus léger qu'une image transparente.

8
iagreen

Fait après beaucoup de R&D:

fragment_one.xml devrait ressembler à:

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:id="@+id/scrollViewParent"
    Android:orientation="vertical" >

    <LinearLayout
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        Android:orientation="vertical" >

        <RelativeLayout
            Android:layout_width="match_parent"
            Android:layout_height="400dip" >

            <com.google.Android.gms.maps.MapView
                Android:id="@+id/mapView"
                Android:layout_width="match_parent"
                Android:layout_height="match_parent" />

            <View
                Android:id="@+id/customView"
                Android:layout_width="fill_parent"
                Android:layout_height="fill_parent"
                Android:background="@Android:color/transparent" />
        </RelativeLayout>

        <!-- Your other elements are here -->

    </LinearLayout>

</ScrollView>

Votre Java de FragmentOne.Java ressemble à:

private GoogleMap mMap;
private MapView mapView;
private UiSettings mUiSettings;
private View customView

onCreateView

mapView = (MapView) rootView.findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);

if (mapView != null) {
   mMap = mapView.getMap();
   mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
   mUiSettings = mMap.getUiSettings();
   mMap.setMyLocationEnabled(true);
   mUiSettings.setCompassEnabled(true); 
   mUiSettings.setMyLocationButtonEnabled(false);
}


scrollViewParent = (ScrollView)rootView.findViewById(R.id.scrollViewParent);
customView = (View)rootView.findViewById(R.id.customView);

customView.setOnTouchListener(new View.OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                int action = event.getAction();
                switch (action) {
                    case MotionEvent.ACTION_DOWN:
                        // Disallow ScrollView to intercept touch events.
                        scrollViewParent.requestDisallowInterceptTouchEvent(true);
                        // Disable touch on transparent view
                        return false;

                    case MotionEvent.ACTION_UP:
                        // Allow ScrollView to intercept touch events.
                        scrollViewParent.requestDisallowInterceptTouchEvent(false);
                        return true;

                    case MotionEvent.ACTION_MOVE:
                        scrollViewParent.requestDisallowInterceptTouchEvent(true);
                        return false;

                    default:
                        return true;
                }
            }
        });
3
Hiren Patel

J'ai utilisé ces structures et j'ai surmonté le problème.

J'ai utilisé une vue conteneur pour le fragment de cartes.

<ScrollView
    Android:layout_width="match_parent"
    Android:layout_height="match_parent">

    <LinearLayout
        Android:orientation="vertical"
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content">

        <TextView
            Android:text="Another elements in scroll view1"
            Android:layout_width="wrap_content"
            Android:layout_height="wrap_content" />


        <com.erolsoftware.views.MyMapFragmentContainer
            Android:orientation="vertical"
            Android:layout_width="match_parent"
            Android:layout_height="250dp">

            <fragment
                xmlns:Android="http://schemas.Android.com/apk/res/Android"
                xmlns:tools="http://schemas.Android.com/tools"
                Android:layout_width="match_parent"
                Android:layout_height="match_parent"
                Android:id="@+id/eventMap"
                tools:context="com.erolsoftware.eventapp.EventDetails"
                Android:name="com.google.Android.gms.maps.SupportMapFragment"/>

        </com.erolsoftware.views.MyMapFragmentContainer>

        <TextView
            Android:text="Another elements in scroll view2"
            Android:layout_width="wrap_content"
            Android:layout_height="wrap_content" />



    </LinearLayout>




</ScrollView>

La classe de conteneur:

public class MyMapFragmentContainer extends LinearLayout {


    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev)
    {
        if (ev.getActionMasked() == MotionEvent.ACTION_DOWN)
        {
            ViewParent p = getParent();
            if (p != null)
                p.requestDisallowInterceptTouchEvent(true);
        }

        return false;
    }

    public MyMapFragmentContainer(Context context) {
        super(context);
    }

    public MyMapFragmentContainer(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MyMapFragmentContainer(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

}
2
Erkan Erol

Pas besoin de lutter avec customScrollViews et des fichiers de mise en page transparents. utilisez simplement une version plus légère de google map et votre problème sera résolu.

  map:liteMode="true"

ajoutez la propriété ci-dessus à l'intérieur du fragment de carte dans votre fichier de mise en page. et le problème sera résolu.

1
Hammad Tariq
<ScrollView
            Android:layout_width="match_parent"
    ::
    ::
    ::
      <FrameLayout
            Android:id="@+id/map_add_business_one_rl"
            Android:layout_width="match_parent"
            Android:layout_height="100dp"
         >
                        <fragment

                            Android:id="@+id/map"
                            Android:name="com.google.Android.gms.maps.SupportMapFragment"
                            Android:layout_width="match_parent"
                            Android:layout_height="match_parent"
                            Android:layout_marginTop="-100dp"
                            Android:layout_marginBottom="-100dp"

                            />

        </FrameLayout>

    ::
    ::
    ::
     </ScrollView>
0
Faakhir

Pour la deuxième partie de la question - vous pouvez dériver une classe de fragments de SupportMapFragment et l'utiliser à la place dans votre mise en page. Vous pouvez ensuite remplacer Fragment # onCreateView , et y instancier votre MapView personnalisé.

Si cela ne fonctionne pas, vous pouvez toujours créer votre propre fragment - il vous suffit alors de prendre soin d'appeler vous-même toutes les méthodes du cycle de vie (onCreate, onResume, etc.). Cette réponse a plus de détails.

0
Ralf