MapView in einer ScrollView?


73

Ich möchte eine MapView in einer ScrollView haben, aber wenn ich versuche, die Karte zu scrollen, hat die ScrollView Vorrang! Gibt es eine Möglichkeit, der MapView-Priorität beim Scrollen innerhalb der Karte und der ScrollView eine andere Priorität zuzuweisen?

Vielen Dank!


Wie ist dein Layout? Können Sie einen Screenshot des endgültigen Layouts veröffentlichen, das gerendert wird?
Aman Alam

1
MapView übernimmt automatisch das Scrollen ....
Sandy

2
Ich kenne. Ich habe eine ScrollView, die viele verschiedene Dinge enthält, einschließlich einer MapView. Das Problem ist, dass wenn ich versuche, in der Kartenansicht zu scrollen, die Bildlaufansicht diese überschreibt.
Cesar

Ich habe das auch in meiner App gemacht, aber keine Lösung gefunden, also habe ich die Kartenansicht außerhalb der Bildlaufansicht und den Rest des Layouts in der Bildlaufansicht platziert.
Sandy

1
Nichts Neues für andere Antworten, aber ich habe einen Überblick darüber erstellt, wie ich das gelöst habe. gist.github.com/Sottti/890daaeead1bd4784dfce7066a9011aa
Sotti

Antworten:


98

Ich habe seit 10 Tagen das gleiche Problem, aber vor ein paar Minuten habe ich eine Lösung gefunden !! Hier ist die Lösung. Ich habe eine benutzerdefinierte MapView erstellt und onTouchEvent () wie folgt überschrieben.

@Override
public boolean onTouchEvent(MotionEvent ev) {
    int action = ev.getAction();
    switch (action) {
    case MotionEvent.ACTION_DOWN:
        // Disallow ScrollView to intercept touch events.
        this.getParent().requestDisallowInterceptTouchEvent(true);
        break;

    case MotionEvent.ACTION_UP:
        // Allow ScrollView to intercept touch events.
        this.getParent().requestDisallowInterceptTouchEvent(false);
        break;
    }

    // Handle MapView's touch events.
    super.onTouchEvent(ev);
    return true;
}

2
@Luizje: Das Blinken wird durch die Hintergrundfarben verursacht, die Sie für jede Ansicht verwenden. Stellen Sie also sicher, dass Sie die äußerste Ansicht mit der Farbe Corect BG haben.
Aimango

37
Wenn es bei Ihnen nicht funktioniert, versuchen Sie stattdessen, die dispatchTouchEvent-Methode zu überschreiben (gleiche Implementierung, ändern Sie einfach den Superaufruf am Ende). Vielen Dank.
Rotem

2
@Rotem Ihre Lösung hat bei mir funktioniert. Ich hatte eine com.google.android.gms.maps.MapView in einer ScrollView und es funktionierte nicht mit dem obigen Code. Ich habe diese Klasse erweitert und Ihre Lösung mit dem Überschreiben der dispatchTouchEvent-Methode geschrieben.
Tooroop

2
@Rotem: Es funktioniert mit dispatchTouchEvent. Danke Kumpel .. Njoyee Codierung.
MS.

3
@Rotem, dein Kommentar hat meinen Arsch gerettet. Danke Alter.
Aung Pyae

47

Eine bessere / einfachere Möglichkeit, dies zu tun, ohne einzelne Berührungsereignisse zu manipulieren. Dies funktioniert, wenn Sie MapView verwenden:

  @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        /**
         * Request all parents to relinquish the touch events
         */
        getParent().requestDisallowInterceptTouchEvent(true);
        return super.dispatchTouchEvent(ev);
    }

Volle Klasse:

public class CustomMapView extends MapView {

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

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

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

    public CustomMapView(Context context, GoogleMapOptions options) {
        super(context, options);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        /**
         * Request all parents to relinquish the touch events
         */
        getParent().requestDisallowInterceptTouchEvent(true);
        return super.dispatchTouchEvent(ev);
    }
}

Wenn Sie ein MapFragment verwenden, können Sie das Fragment in eine benutzerdefinierte Ansicht einfügen und dispatchTouchEvent()den requestDisallowInterceptTouchEventAnruf tätigen .


2
Danke Chef. Es ist perfekt für mich.
Shohel Rana

1
Dies ist die beste Antwort, danke.
Chathura Wijesinghe

Schön, obwohl nur requestDisallowInterceptTouchEventfür notwendig MotionEvent.ACTION_DOWN.
Arekolek

21

Erstellen Sie Ihre eigene Karte und verwenden Sie sie. Es funktioniert voll für mich.

public class CustomMapView extends MapView {

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

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    switch (ev.getAction()) {
    case MotionEvent.ACTION_UP:
        System.out.println("unlocked");
        this.getParent().requestDisallowInterceptTouchEvent(false);
        break;
    case MotionEvent.ACTION_DOWN:
        System.out.println("locked");
        this.getParent().requestDisallowInterceptTouchEvent(true);
        break;
    }
    return super.dispatchTouchEvent(ev);
}} 

In Ihrem Layout-XML,

<com.yourpackage.xxxx.utils.CustomMapView
                android:id="@+id/customMap"
                android:layout_width="match_parent"
                android:layout_height="400dp"
                android:layout_marginLeft="5dp"
                android:layout_marginRight="5dp"
                />

15

Für diejenigen, die den gesamten Arbeitscode wollen. hier ist es

Benutzerdefinierte Kartenansichtsklasse

public class CustomMapView extends MapView {

private ViewParent mViewParent;
public CustomMapView(Context context) {
    super(context);
}

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

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

public CustomMapView(Context context, GoogleMapOptions options) {
    super(context, options);
}

public void setViewParent(@Nullable final ViewParent viewParent) { //any ViewGroup
    mViewParent = viewParent;
}

@Override
public boolean onInterceptTouchEvent(final MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            if (null == mViewParent) {
                getParent().requestDisallowInterceptTouchEvent(true);
            } else {
                mViewParent.requestDisallowInterceptTouchEvent(true);
            }
            break;
        case MotionEvent.ACTION_UP:
            if (null == mViewParent) {
                getParent().requestDisallowInterceptTouchEvent(false);
            } else {
                mViewParent.requestDisallowInterceptTouchEvent(false);
            }
            break;
        default:
            break;
    }

    return super.onInterceptTouchEvent(event);
  }
}

Aktivitätslayout xml

  <ScrollView
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <location.to.your.CustomMapView
        android:id="@+id/mapView"
        android:layout_width="match_parent"
        android:layout_height="250dp"
         />

</ScrollView>

Instanziieren der benutzerdefinierten Kartenklasse in Ihrer Aktivität oder Ihrem Fragment

       CustomMapView mapView = (CustomMapView) findViewById(R.id.mapView);

Das ist es zu genießen


2
Die anderen Lösungen haben bei mir nicht funktioniert, diese hier! Danke vielmals!
Ruben2112

9

Sie können eine benutzerdefinierte MapView wie folgt erstellen:

public class CustomMapView extends MapView {

    private MapFragment.ControlLock mCallbackControl;

    public CustomMapView(Context context) {
        this(context, null);
    }

    public CustomMapView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

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

    public CustomMapView(Context context, GoogleMapOptions options) {
        super(context, options);
    }

    public void setCallback(MapFragment.ControlLock callbackControl) {
        this.mCallbackControl = callbackControl;
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {

        switch (event.getAction()) {
            case MotionEvent.ACTION_UP:
                System.out.println("unlocked");
                mCallbackControl.unlock(); /* Interface */
                break;
            case MotionEvent.ACTION_DOWN:
                System.out.println("locked");
                mCallbackControl.lock(); /* Interface */
                break;
        }

        return super.dispatchTouchEvent(event);
    }
}

hat meinen Tag gerettet. Funktioniert auch für osmdroid mapview. groß.
Yubaraj Poudel

8

Ich habe versucht, MapView.onTouchEvent (...) zu überschreiben, aber es hat bei mir nicht funktioniert. Hier ist Code, der gut funktioniert (MapView.onInterceptTouchEvent (...) überschreiben):

public class MyMapView extends MapView {
    private ViewParent mViewParent;

//add constructors here

    public void setViewParent(@Nullable final ViewParent viewParent) { //any ViewGroup
            mViewParent = viewParent;
    }

    @Override
        public boolean onInterceptTouchEvent(final MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    if (null == mViewParent) {
                        getParent().requestDisallowInterceptTouchEvent(true);
                    } else {
                        mViewParent.requestDisallowInterceptTouchEvent(true);
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    if (null == mViewParent) {
                        getParent().requestDisallowInterceptTouchEvent(false);
                    } else {
                        mViewParent.requestDisallowInterceptTouchEvent(false);
                    }
                    break;
                default:
                    break;
            }

            return super.onInterceptTouchEvent(event);
        }
}

Da ich viele verschachtelte Ansichtsgruppen habe, hat diese Lösung für mich einwandfrei funktioniert.
Roisgoen

Das Überschreiben onInterceptTouchEvent()hat auch bei mir funktioniert, wohingegen onTouchEvent()es nicht funktioniert hat. Aber ich brauchte den mViewParent nicht, es scheint, dass requestDisallowInterceptTouchEvent()er in der Ansichtshierarchie weitergegeben wird.
Klemens Zleptnig

2

Sie können die MapView einfach in ein Layout selbst einfügen und onTouch überschreiben oder einen Click-Listener festlegen - der einfachste Weg für mich, da ich die gesamte MapView in meiner ScrollView berühren musste.


1

Wenn Sie eine Kartenansicht in der Bildlaufansicht haben, müssen Sie die folgenden Parameter in der Kartenansicht explizit erwähnen:

mMapView.setClickable(true);
mMapView.setFocusable(true);
mMapView.setDuplicateParentStateEnabled(false);

Aber dann, nachdem Sie es angegeben haben und die Kartenansicht wird nicht mehr scrollbar

1

Wenn jemand diese Klasse in Kotlin will.
Ich habe dispatchTouchEventwie von @rotem vorgeschlagen verwendet

class CustomMapView : MapView {
           constructor(context: Context):
            super(context)
    constructor(context: Context, googleMapOptions: GoogleMapOptions):
            super(context, googleMapOptions)
    constructor(context: Context, attributeSet: AttributeSet):
            super(context, attributeSet)
    constructor(context: Context, attributeSet: AttributeSet, int: Int):
            super(context, attributeSet, int)

    override fun dispatchTouchEvent(event: MotionEvent?): Boolean {
        Log.d("CustomWebView", "touchevent")
        when(event?.action) {
            MotionEvent.ACTION_UP -> {
                Log.d("CustomWebView", "disallow Intercept")
                parent.requestDisallowInterceptTouchEvent(false)
            }
            MotionEvent.ACTION_DOWN -> {
                Log.d("CustomWebView", "allow Intercept")
                parent.requestDisallowInterceptTouchEvent(true)
            }
        }
        return super.dispatchTouchEvent(event)
    }
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.