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
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
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);
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é.
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.
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);
}
});
}
});
}