ScrollView中的Google Maps API v2 SupportMapFragment - 用户无法垂直滚动地图

In-*_* Yi 51 android scala google-maps-android-api-2

我正在尝试将Google地图放在滚动视图中,以便用户可以向下滚动其他内容以查看地图.问题是这个滚动视图占用了所有垂直触摸事件,因此地图的UI体验变得非常奇怪.

我知道在谷歌地图的V1中,您可以覆盖onTouch或setOnTouchListener以在MotionEvent.ACTION_DOWN上调用requestDisallowInterceptTouchEvent.我试图用V2实现类似的技巧无济于事.

到目前为止,我尝试过:

  • 覆盖SupportMapFragment,在onCreateView中,为View设置触摸侦听器
  • 调用SupportMapFragment实例的.getView(),然后调用setOnTouchListener
  • 环绕相对布局或框架布局,使用透明视图或图像视图遮罩片段

这些都没有解决滚动问题.我在这里错过了什么吗?如果有人在滚动视图中有一个地图的工作示例,请您分享代码示例吗?

Lak*_*ksh 136

在mapview片段上应用透明图像.

<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>   
Run Code Online (Sandbox Code Playgroud)

然后设置requestDisallowInterceptTouchEvent(true)主ScrollView.当用户触摸透明图像并移动时禁用透明图像上的触摸MotionEvent.ACTION_DOWN,MotionEvent.ACTION_MOVE以便地图片段可以进行触摸事件.

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;
        }   
    }
});
Run Code Online (Sandbox Code Playgroud)

这对我有用.希望它可以帮助你..

  • 保存我的截止日期:))这有效,而不是我在stackoverflow上找到的所有其他解决方案.谢谢 (4认同)
  • 很好的答案! (2认同)
  • 简单而辉煌! (2认同)
  • 叠加层不需要是ImageView,简单的View就可以了. (2认同)

小智 15

我遇到了类似的问题,并提出了一个基于In-Ho Yi和上面的ДанаилДимитров答案的更通用的工作解决方案.

public class CustomScrollView extends ScrollView {

    List<View> mInterceptScrollViews = new ArrayList<View>();

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

    public void addInterceptScrollView(View view) {
        mInterceptScrollViews.add(view);
    }

    public void removeInterceptScrollView(View view) {
        mInterceptScrollViews.remove(view);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {

        // check if we have any views that should use their own scrolling
        if (mInterceptScrollViews.size() > 0) {
            int x = (int) event.getX();
            int y = (int) event.getY();
            Rect bounds = new Rect();

            for (View view : mInterceptScrollViews) {
                view.getHitRect(bounds);
                if (bounds.contains(x, y + scrollY)) {
                    //were touching a view that should intercept scrolling
                    return false;
                }
            }
        }

        return super.onInterceptTouchEvent(event);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 我认为这是最完整,最干净的答案.它运作良好,应该是公认的答案.如果你有一个map作为<fragment>内部布局,你应该通过fragmentObject.getView()将片段的视图传递给CustomScrollView (2认同)

In-*_* Yi 9

谢谢你的建议,

经过多次尝试和错误,拔掉我的头发,咒骂显示器和我糟糕的Android测试手机,我想如果我自定义ScrollView,重写onInterceptTouchEvent,当事件在地图视图上时我们返回false什么,然后地图上的滚动确实按预期发生.

class MyScrollView(c:Context, a:AttributeSet) extends ScrollView(c,a) {
  val parent = c.asInstanceOf[MyActivity]
  override def onInterceptTouchEvent(ev:MotionEvent):Boolean = {
    var bound:Rect = new Rect()
    parent.mMap.getHitRect(bound)
    if(bound.contains(ev.getX.toInt,ev.getY.toInt))
      false
    else
      super.onInterceptTouchEvent(ev)
  }
}
Run Code Online (Sandbox Code Playgroud)

这段代码在Scala中,但你明白了.

注意我最终使用了原始地图视图(如android-sdks\extras\google\google_play_services\samples\maps\src\com\example\mapdemoRawMapViewDemoActivity.java中所示).猜猜你可以用片段做同样的事情,我从来没有喜欢片段.

我认为Google欠我一个道歉.


小智 5

我有同样的问题,所以这里是我如何使用解决方案作为Java代码,以防任何人需要它.您只需在使用时设置mapView字段.

import com.google.android.gms.maps.MapView;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ScrollView;

public class ScrollViewWithMap extends ScrollView
{
    public MapView mapView;

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

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev)
    {
        if (mapView == null)
            return super.onInterceptTouchEvent(ev);

        if (inRegion(ev.getRawX(), ev.getRawY(), mapView))
            return false;

        return super.onInterceptTouchEvent(ev);
    }

    private boolean inRegion(float x, float y, View v)
    {
        int[] mCoordBuffer = new int[]
        { 0, 0 };

        v.getLocationOnScreen(mCoordBuffer);

        return mCoordBuffer[0] + v.getWidth() > x && // right edge
                mCoordBuffer[1] + v.getHeight() > y && // bottom edge
                mCoordBuffer[0] < x && // left edge
                mCoordBuffer[1] < y; // top edge
    }
}
Run Code Online (Sandbox Code Playgroud)