ScrollView内的Google Maps API v2 SupportMapFragment – 用户不能垂直滚动地图

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

我知道在谷歌地图的V1,你可以重写onTouch,或setOnTouchListener调用motionEvent.ACTION_DOWN的requestDisallowInterceptTouchEvent。 我试图用V2来实现类似的技巧无济于事。

到目前为止我已经尝试过:

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

这些都没有解决滚动问题。 我在这里错过了什么? 如果任何人有滚动视图内的地图的工作示例,请你分享代码示例?

在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> 

然后为主ScrollView设置requestDisallowInterceptTouchEvent(true) 。 当用户触摸透明图像并移动禁用透明图像上的MotionEvent.ACTION_DOWNMotionEvent.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; } } }); 

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

我遇到了类似的问题,并提出了一个更一般的工作解决scheme,基于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)) { //were touching a view that should intercept scrolling return false; } } } return super.onInterceptTouchEvent(event); } } 

谢谢你的build议,

经过多次尝试和错误,拔掉我的头发,并在监视器和我可怜的Androidtesting手机发誓,我想如果我定制滚动视图,重写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) } } 

这个代码是在斯卡拉,但你明白了。

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

我认为Google欠我一个道歉。

我有同样的问题,所以这里是我如何使用解决scheme作为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 } } 

接受的答案在我的情况下是行不通的。 客人的答案既没有(但几乎)。 如果其他人尝试这个客人的答案的编辑版本。

如果有人在计算hitbox时需要使用它,我已经注释了这个动作栏的高度。

 public class InterceptableScrollView extends ScrollView { List<View> mInterceptScrollViews = new ArrayList<View>(); public InterceptableScrollView(Context context) { super(context); } public InterceptableScrollView(Context context, AttributeSet attrs) { super(context, attrs); } public InterceptableScrollView(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); } private int getRelativeTop(View myView) { if (myView.getParent() == this) return myView.getTop(); else return myView.getTop() + getRelativeTop((View) myView.getParent()); } private int getRelativeLeft(View myView) { if (myView.getParent() == this) return myView.getLeft(); else return myView.getLeft() + getRelativeLeft((View) myView.getParent()); } @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(); /* int actionBarHeight = 0; TypedValue tv = new TypedValue(); if (getContext().getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) { actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data,getResources().getDisplayMetrics()); } */ int viewLocationY = 0; int viewLocationX = 0; int relativeTop = 0; int relativeLeft = 0; for (View view : mInterceptScrollViews) { relativeTop = getRelativeTop((View) view.getParent()); relativeLeft = getRelativeLeft((View) view.getParent()); viewLocationY = relativeTop - getScrollY(); viewLocationX = relativeLeft - getScrollX(); if (view.getHeight() + viewLocationY > y && y > viewLocationY && view.getWidth() + viewLocationX > x && x > viewLocationX) { return false; } } } return super.onInterceptTouchEvent(event); } } 

如果您再次不需要透明的图像,则改进代码:

 // gmap hack for touch and scrollview final ScrollView mainScrollView = (ScrollView) rootView.findViewById(R.id.scrollView); (rootView.findViewById(R.id.fixTouchMap)).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; } } }); 

上面列出的大部分选项对我来说都不起作用,但是对于我来说,以下事实certificate是一个很好的解决scheme:

奶酪男爵解决scheme

我也必须实现稍微不同的实现,因为我使用的地图片段,使事情稍微复杂一些,但很容易工作。