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

Android Google Maps API v2 SupportMapFragment在ScrollView中-用户无法垂直滚动地图,android,scala,google-maps-android-api-2,Android,Scala,Google Maps Android Api 2,我试图将谷歌地图放在滚动视图中,这样用户就可以向下滚动其他内容来查看地图。问题是,这个滚动视图正在吞噬所有垂直触摸事件,因此map的UI体验变得非常怪异 我知道在google地图的V1中,您可以重写onTouch或setOnTouchListener,在MotionEvent.ACTION\u关闭时调用RequestDisallowWinterCeptTouchEvent。我试图用V2实现类似的技巧,但没有成功 到目前为止,我已经尝试: 覆盖SupportMapFragment,并在onCre

我试图将谷歌地图放在滚动视图中,这样用户就可以向下滚动其他内容来查看地图。问题是,这个滚动视图正在吞噬所有垂直触摸事件,因此map的UI体验变得非常怪异

我知道在google地图的V1中,您可以重写onTouch或setOnTouchListener,在MotionEvent.ACTION\u关闭时调用RequestDisallowWinterCeptTouchEvent。我试图用V2实现类似的技巧,但没有成功

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

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

这些都不能解决滚动问题。我是不是遗漏了什么?如果任何人在滚动视图中有地图的工作示例,请分享代码示例好吗?

谢谢您的建议

经过多次尝试和错误,我脱掉头发,对着显示器和我可怜的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)
  }
}
这段代码是用Scala编写的,但是你知道了

注意,我最终使用了一个原始地图视图(如android SDK\extras\google\google\u play\u services\samples\maps\src\com\example\mapdemawViewDemoActivity.java所示)。我猜你也可以用碎片做同样的事情,我只是一开始就不喜欢碎片


我认为谷歌应该向我道歉。

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

这对我有用。希望它对您有所帮助。

我也有同样的问题,所以下面是我如何将解决方案作为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
    }
}
import com.google.android.gms.maps.MapView;
导入android.content.Context;
导入android.util.AttributeSet;
导入android.view.MotionEvent;
导入android.view.view;
导入android.widget.ScrollView;
公共类ScrollView WithMap扩展了ScrollView
{
公共地图视图;
公共ScrollViewWithMap(上下文、属性集属性)
{
超级(上下文,attrs);
}
@凌驾
公共布尔值onInterceptTouchEvent(MotionEvent ev)
{
如果(mapView==null)
返回超级onInterceptTouchEvent(ev);
if(在区域(ev.getRawX(),ev.getRawY(),mapView))中)
返回false;
返回超级onInterceptTouchEvent(ev);
}
区域中的私有布尔值(浮点x、浮点y、视图v)
{
int[]mCoordBuffer=新int[]
{ 0, 0 };
v、 getLocationOnScreen(mCoordBuffer);
返回mCoordBuffer[0]+v.getWidth()>x&&//右边缘
mCoordBuffer[1]+v.getHeight()>y&&//底边
mCoordBuffer[0]
我遇到了类似的问题,并根据上述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);
    }
}
公共类CustomScrollView扩展了ScrollView{
List mInterceptScrollViews=newarraylist();
公共自定义滚动视图(上下文){
超级(上下文);
}
公共CustomScrollView(上下文、属性集属性){
超级(上下文,attrs);
}
公共CustomScrollView(上下文上下文、属性集属性、int-defStyle){
超级(上下文、属性、定义样式);
}
公共void addInterceptScrollView(视图){
mInterceptScrollViews.add(视图);
}
公共无效删除InterceptScrollView(视图){
mInterceptScrollViews.remove(视图);
}
@凌驾
公共布尔值onInterceptTouchEvent(MotionEvent){
//检查是否有任何视图应该使用自己的滚动
if(mInterceptScrollViews.size()>0){
int x=(int)event.getX();
int y=(int)event.getY();
Rect bounds=new Rect();
对于(视图:MinterceptScrollView){
view.getHitRect(边界);
if(bounds.contains(x,y+滚动)){
//正在触摸一个应该拦截滚动的视图
返回false;
}
}
}
返回super.onInterceptTouchEvent(事件);
}
}

如果不再需要透明图像,请改进代码:

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

被接受的答案在我的情况下不起作用。客人的回答没有(但几乎没有)。如果其他人也是这样,请尝试此客人答案的编辑版本

如果有人需要在计算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);
    }
}
公共类InterceptableScrollView扩展了ScrollView{
List mInterceptScrollViews=newarraylist();
public InterceptableScrollView(上下文){
超级(上下文);
}
public InterceptableScrollView(上下文、属性集属性){
超级(上下文,attrs);
}
public InterceptableScrollView(上下文上下文、属性集属性、int-defStyle){
超级(上下文、属性、定义样式);
}
公共void addInterceptScrollView(视图){
mInterceptScrollViews.add(视图);
}
公共无效删除InterceptScrollView(视图){
mInterceptScrollViews.remove(视图);
}
私有int getRelativeTop(视图myView){
if(myView.getParent()==此)
返回myView.getTop();
其他的
返回myView.getTop()+getRelativeTop((视图)myView.getParent());
}
私有int getRelativeLeft(查看myView){
if(myView.getParent()==此)
返回myView。
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);
    }
}
<fragment
        android:id="@+id/map_with_scroll_fix"
        android:name="com.myapplication.maputil.GoogleMapWithScrollFix"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
package com.myapplication.maputil;

import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;

import com.google.android.gms.maps.SupportMapFragment;
    public class GoogleMapWithScrollFix extends SupportMapFragment {
        private OnTouchListener mListener;

        @Override
        public View onCreateView(LayoutInflater layoutInflater, ViewGroup viewGroup, Bundle savedInstance) {
            View layout = super.onCreateView(layoutInflater, viewGroup, savedInstance);

            TouchableWrapper touchableWrapper = new TouchableWrapper(getActivity());

            touchableWrapper.setBackgroundColor(getResources().getColor(android.R.color.transparent));

            ((ViewGroup) layout).addView(touchableWrapper,
                    new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));

            return layout;
        }

        public void setListener(OnTouchListener listener) {
            mListener = listener;
        }

        public interface OnTouchListener {
            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);
            }
        }
    }
((GoogleMapWithScrollFix) getSupportFragmentManager()
                .findFragmentById(R.id.map_with_scroll_fix)).getMapAsync(new OnMapReadyCallback() {
            @Override
            public void onMapReady(GoogleMap googleMap) {
                ScrollView mScrollView = findViewById(R.id.scrollview); //parent scrollview in xml, give your scrollview id value
                ((GoogleMapWithScrollFix) getSupportFragmentManager()
                        .findFragmentById(R.id.map_with_scroll_fix)).setListener(new GoogleMapWithScrollFix.OnTouchListener() {
                    @Override
                    public void onTouch() {
                        //Here is the magic happens.
                        //we disable scrolling of outside scroll view here
                        mScrollView.requestDisallowInterceptTouchEvent(true);
                    }
                });
            }
        });
override fun onTouch(v: View?, event: MotionEvent?): Boolean {
    when (v?.id) {
        R.id.transparent_image -> {

            when (event?.action) {
                MotionEvent.ACTION_DOWN -> {
                    reportScrollView.requestDisallowInterceptTouchEvent(true)
                    return false
                }
                MotionEvent.ACTION_UP -> {
                    reportScrollView.requestDisallowInterceptTouchEvent(false)
                    return true
                }
                MotionEvent.ACTION_MOVE -> {
                    reportScrollView.requestDisallowInterceptTouchEvent(true)
                    return false
                }
                else -> return true
            }
        }
        else -> {
            return true
        }
    }
}