web-dev-qa-db-fra.com

comment définir le fragment de carte Google dans la vue de défilement

Je veux définir un fragment de carte Google à l'intérieur de ScrollView vertical, lorsque je fais la carte ne zoom pas verticalement, comment puis-je remplacer l'écouteur d'événements tactiles sur MapView sur l'écouteur de ScrollView?

Voici mon code xml:

  <ScrollView  Android:layout_height="wrap_content"
    Android:layout_width="fill_parent"
     Android:layout_above="@id/footer"
    Android:layout_below="@id/title_horizontalScrollView">

   ///other things



<fragment 
    Android:id="@+id/map"
    Android:layout_width="fill_parent"
    Android:layout_height="300dp"
    class="com.google.Android.gms.maps.SupportMapFragment"
    />

  //other things
33
Malo

Créez un SupportMapFragmet personnalisé afin que nous puissions remplacer son événement tactile:

WorkaroundMapFragment.Java

import Android.content.Context;
import Android.os.Bundle;
import Android.widget.FrameLayout;

import Android.view.LayoutInflater;
import Android.view.MotionEvent;
import Android.view.View;
import Android.view.ViewGroup;

import com.google.Android.gms.maps.SupportMapFragment;

public class WorkaroundMapFragment extends SupportMapFragment {
    private OnTouchListener mListener;

    @Override
    public View onCreateView(LayoutInflater layoutInflater, ViewGroup viewGroup, Bundle savedInstance) {
        View layout = super.onCreateView(layoutInflater, viewGroup, savedInstance);

        TouchableWrapper frameLayout = new TouchableWrapper(getActivity());

        frameLayout.setBackgroundColor(getResources().getColor(Android.R.color.transparent));

        ((ViewGroup) layout).addView(frameLayout,
                new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));

        return layout;
    }

    public void setListener(OnTouchListener listener) {
        mListener = listener;
    }

    public interface OnTouchListener {
        public abstract void onTouch();
    }

    public class TouchableWrapper extends FrameLayout {

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

        @Override
        public boolean dispatchTouchEvent(MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    mListener.onTouch();
                    break;
                case MotionEvent.ACTION_UP:
                    mListener.onTouch();
                    break;
            }
            return super.dispatchTouchEvent(event);
        }
    }
}

Dans cette classe ci-dessus, nous interceptons l'événement tactile en utilisant la classe TouchableWrapper qui étend le FrameLayout. Il existe également un écouteur personnalisé OnTouchListener pour envoyer l'événement tactile à l'activité principale MyMapActivity qui gère la carte. Lorsqu'un événement tactile s'est produit, dispatchTouchEvent sera appelé et l'auditeur mListener le gérera.

Remplacez ensuite la classe de fragment en xml par ce class="packagename.WorkaroundMapFragment" au lieu de com.google.Android.gms.maps.SupportMapFragment

Ensuite, dans votre activité, initialisez la carte comme suit:

private GoogleMap mMap;

dans onCreate, procédez comme suit:

  // check if we have got the googleMap already
  if (mMap == null) {
        SupportMapFragment mapFragment = (WorkaroundMapFragment) getChildFragmentManager().findFragmentById(R.id.map);
        mapFragment.getMapAsync(new OnMapReadyCallback() {
            Override
                public void onMapReady(GoogleMap googleMap)
                    {
                        mMap = googleMap;
                        mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
                        mMap.getUiSettings().setZoomControlsEnabled(true);

                        mScrollView = findViewById(R.id.scrollMap); //parent scrollview in xml, give your scrollview id value
                        ((WorkaroundMapFragment) getChildFragmentManager().findFragmentById(R.id.map))
                                .setListener(new WorkaroundMapFragment.OnTouchListener() {
                            @Override
                            public void onTouch()
                                {
                                        mScrollView.requestDisallowInterceptTouchEvent(true);
                                }
                            });
                    }
        });
    }

pdate: Réponse mise à jour pour getMapAsync basée sur la réponse de @ javacoder123

100
Alok Nair

Juste faire CustomScrollView.class,

public class CustomScrollView extends ScrollView {

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

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

public CustomScrollView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
}

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    final int action = ev.getAction();
    switch (action) {
        case MotionEvent.ACTION_DOWN:
            //Log.i("CustomScrollView", "onInterceptTouchEvent: DOWN super false" );
            super.onTouchEvent(ev);
            break;

        case MotionEvent.ACTION_MOVE:
            return false; // redirect MotionEvents to ourself

        case MotionEvent.ACTION_CANCEL:
            // Log.i("CustomScrollView", "onInterceptTouchEvent: CANCEL super false" );
            super.onTouchEvent(ev);
            break;

        case MotionEvent.ACTION_UP:
            //Log.i("CustomScrollView", "onInterceptTouchEvent: UP super false" );
            return false;

        default:
            //Log.i("CustomScrollView", "onInterceptTouchEvent: " + action );
            break;
    }

    return false;
}

@Override
public boolean onTouchEvent(MotionEvent ev) {
    super.onTouchEvent(ev);
    //Log.i("CustomScrollView", "onTouchEvent. action: " + ev.getAction() );
    return true;
  }
}

Puis en xml

<com.app.ui.views.CustomScrollView
     Android:id="@+id/scrollView"
     xmlns:Android="http://schemas.Android.com/apk/res/Android"
     xmlns:app="http://schemas.Android.com/apk/res-auto"
     Android:layout_width="match_parent"
     Android:layout_height="match_parent"
     Android:fillViewport="true"
     Android:orientation="vertical">
</com.app.ui.views.CustomScrollView>

si xml beffore ne fonctionnait pas, changez cela ...

<com.myproyect.myapp.CustomScrollView
        Android:id="@+id/idScrollView"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        Android:fillViewport="true"
        Android:descendantFocusability="beforeDescendants"
        >
</com.myproyect.myapp.CustomScrollView>

comment utiliser par programmation

CustomScrollView myScrollView = (CustomScrollView) findViewById(R.id.idScrollView);
26

Veuillez vous référer à cette réponse: https://stackoverflow.com/a/17317176/48371

Il crée une vue transparente avec la même taille de mapFragment , à la même position avec mapFragment , puis appelez requestDisallowInterceptTouchEvent (true), empêchant ses ancêtres d'intercepter les événements tactiles.

Ajoutez une vue transparente sur le fragment mapview :

<ScrollView>
    ...
         <FrameLayout
             Android:layout_width="match_parent"
             Android:layout_height="300dp">
             <FrameLayout
                 Android:id="@+id/fl_google_map"
                 Android:layout_width="match_parent"
                 Android:layout_height="match_parent" />
             <!-- workaround to make google map scrollable -->
             <View
                 Android:id="@+id/transparent_touch_panel"
                 Android:layout_width="match_parent"
                 Android:layout_height="match_parent" />
         </FrameLayout>
</ScrollView>

Définissez l'écouteur tactile pour cette vue transparente:

    var transparentTouchPanel = view.FindViewById (Resource.Id.transparent_touch_panel);
    transparentTouchPanel.SetOnTouchListener (this);

....

public bool OnTouch (View v, MotionEvent e) {
    switch (e.Action) {
    case MotionEventActions.Up:
        v.Parent.RequestDisallowInterceptTouchEvent (false);
        break;
    default:
        v.Parent.RequestDisallowInterceptTouchEvent (true);
        break;
    }

    return false;
}

Je pensais RequestDisallowInterceptTouchEvent pourrait fonctionner en étant invoqué une seule fois, mais apparemment, il doit être appelé pour CHAQUE événement tactile, c'est pourquoi il doit être placé à l'intérieur de onTouchEvent. Et le parent propagera cette demande au parent du parent.

J'ai essayé de définir l'écouteur d'événement tactile pour fl_google_map ou pour mapFragment.getView (). Aucun d'eux n'a fonctionné, donc la création d'une vue de frère transparente est une solution de contournement tolérable pour moi.

J'ai essayé, cette solution fonctionne parfaitement. Vérifiez les commentaires sous message d'origine si vous ne me croyez pas. Je préfère cette méthode car elle n'a pas besoin de créer un SupportMapFragmet personnalisé.

3
Chandler

Ma suggestion est d'utiliser une version plus légère de google map pour faire face à cette situation. cela a résolu mon problème.

ajoutez cet attribut en fragment.

 map:liteMode="true"

et mon problème a été résolu. j'ai également ajouté customScrollView en plus de cela. mais après avoir placé la propriété liteMode, mon problème a été résolu.

3
Hammad Tariq

Mise à jour

@ Alok Nair's réponse est très bonne cependant, la méthode .getMap () ne fonctionne plus à partir de Android 9.2 et plus. Changez la méthode getMap en .getMapAsync et ajoutez du code dans la méthode onMapReady

Solution mise à jour, qui fonctionne dans les fragments

if (gMap == null)
        {
          getChildFragmentManager().findFragmentById(R.id.map);
            SupportMapFragment mapFragment = (WorkaroundMapFragment) getChildFragmentManager().findFragmentById(R.id.map);
            mapFragment.getMapAsync(new OnMapReadyCallback()
            {
                @Override
                public void onMapReady(GoogleMap googleMap)
                {
                    gMap = googleMap;
                    gMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
                    gMap.getUiSettings().setZoomControlsEnabled(true);

                    mScrollView = mView.findViewById(R.id.advertScrollView); //parent scrollview in xml, give your scrollview id value
                    ((WorkaroundMapFragment) getChildFragmentManager().findFragmentById(R.id.map))
                            .setListener(new WorkaroundMapFragment.OnTouchListener()
                            {
                                @Override
                                public void onTouch()
                                {
                                    mScrollView.requestDisallowInterceptTouchEvent(true);
                                }
                            });
                }
            });
        }
0
javacoder123