comment mettre fragment de carte de google à l'intérieur de la vue scroll
je veux mettre un fragment de carte Google à l'intérieur de vertical ScrollView
, quand je fais la carte ne fait pas de zoom vertical, Comment puis-je outrepasser l'écouteur d'événement touch sur MapView
au cours de l'auditeur 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
6 réponses
Créer un personnalisé SupportMapFragmet 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 touch en utilisant la classe TouchableWrapper qui étend le FrameLayout. Il y a aussi un écouteur personnalisé OnTouchListener pour envoyer l'événement touch à L'activité principale MyMapActivity qui gère la carte. Lorsque l'événement de contact s'est produit, dispatchTouchEvent sera appelé et l'écouteur mListener s'en chargera.
alors remplacez la classe fragment dans xml par ceci class="packagename.WorkaroundMapFragment"
au lieu de com.google.android.gms.maps.SupportMapFragment
alors dans votre activité initialisez la carte comme suit:
private GoogleMap mMap;
à l'intérieur onCreate faire ceci:
// 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);
}
});
}
});
}
mise à Jour : Réponse mis à jour à getMapAsync basé sur la réponse de @javacoder123
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, Modifiez ceci...
<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 programmaticaly
CustomScrollView myScrollView = (CustomScrollView) findViewById(R.id.idScrollView);
ma suggestion est d'utiliser une version plus légère de google map lorsque vous faites face à cette situation. cela a résolu mon problème.
ajouter cet attribut dans fragment.
map:liteMode="true"
et mon problème s'est résolu. j'ai aussi ajouté customScrollView en plus de cela. mais après avoir placé la propriété de liteMode mon problème résolu.
mise à Jour
@Alok Nair's réponse est très bonne cependant, le .la méthode getMap () ne fonctionne plus à partir d'android 9.2. Changez la méthode getMap en .getMapAsync et ajouter du code dans la méthode onMapReady
solution mise à jour, qui fonctionne en 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);
}
});
}
});
}
reportez-vous à cette réponse: https://stackoverflow.com/a/17317176/4837103
il crée une vue transparente avec la même taille de mapFragment, à la même position avec mapFragment, puis invoque requestdisallowinterceptttouchevent (true), empêchant ses ancêtres d'intercepter les événements tactiles.
ajouter 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éfinir tactile écouteur pour que transparent vue:
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;
}
j'ai pensé RequestDisallowInterceptTouchEvent pourrait fonctionner avec le fait d'être invoqué une seule fois, mais apparemment il doit être appelé pour chaque événement tactile, c'est pourquoi il doit être mis à l'intérieur onTouchEvent. Et le parent propagera cette requête au parent du parent.
j'ai essayé set touch event listener pour fl_google_map, ou pour le mapFragment.getView (). Ni l'un ni l'autre n'a fonctionné, créant ainsi une transparence frère vue est tolérable solution de contournement pour moi.
j'ai essayé, cette solution fonctionne parfaitement. Vérifiez les commentaires sous le message d'origine si vous ne me croyez pas. Je préfère cette façon parce qu'il n'a pas besoin de créer un SupportMapFragmet personnalisé.
Document Android suggéré,
Vous pouvez ajouter l'instar de cette façon:
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="3"
android:orientation="horizontal" >
<fragment
android:id="@+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
</ScrollView>