无论在android上的何处收缩缩放,都要保持地图居中

无论在android上的何处收缩缩放,都要保持地图居中,android,google-maps,location,zooming,Android,Google Maps,Location,Zooming,我希望做一些类似Uber处理收缩缩放事件的方式。无论您在屏幕上挤压到哪里,它都会保持地图居中,并放大中心位置。有没有一种方法可以在不覆盖地图片段的情况下实现这一点?或者我应该禁用贴图的事件,在贴图片段上创建一个覆盖,并处理覆盖中的所有缩放/其他事件吗 就我个人而言,我只会禁用地图上的缩放手势,检测叠加上的挤压,然后将其他所有内容传递到地图 google maps v2 API没有任何明确的自定义缩放处理功能。虽然我相信你可以注入一些东西,但使用覆盖方法可以使你免受谷歌地图的变化,并让你在需要时更

我希望做一些类似Uber处理收缩缩放事件的方式。无论您在屏幕上挤压到哪里,它都会保持地图居中,并放大中心位置。有没有一种方法可以在不覆盖地图片段的情况下实现这一点?或者我应该禁用贴图的事件,在贴图片段上创建一个覆盖,并处理覆盖中的所有缩放/其他事件吗

就我个人而言,我只会禁用地图上的缩放手势,检测叠加上的挤压,然后将其他所有内容传递到地图

google maps v2 API没有任何明确的自定义缩放处理功能。虽然我相信你可以注入一些东西,但使用覆盖方法可以使你免受谷歌地图的变化,并让你在需要时更容易地支持其他地图提供商


(为了完整起见:您也可以处理相机后的更改事件并重新调整中心,但这将是一种令人讨厌的用户体验。)

以下是MechEthan所想的代码

  • 首先,您必须检测叠加视图上的双击

    public class TouchableWrapper extends FrameLayout {
        private final GestureDetector.SimpleOnGestureListener mGestureListener
                = new GestureDetector.SimpleOnGestureListener() {
            @Override
            public boolean onDoubleTap(MotionEvent e) {
    
                //Notify the event bus (I am using Otto eventbus of course) that you have just received a double-tap event on the map, inside the event bus event listener
                EventBus_Singleton.getInstance().post(new EventBus_Poster("double_tapped_map"));
    
                return true;
            }
        };
    
        public TouchableWrapper(Context context) {
            super(context);
            mGestureDetector = new GestureDetectorCompat(context, mGestureListener);
        }
    
        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            mGestureDetector.onTouchEvent(ev);
    
            return super.onInterceptTouchEvent(ev);
        }
    }
    
  • 无论您在何处抓取地图视图,请将该地图视图包装在上面创建的TouchableWrapper中。我就是这样做的,因为我需要将一个mapFragment添加到另一个片段中,所以我需要一个自定义SupportMapFragment来完成这项工作

    public class CustomMap_Fragment extends SupportMapFragment {
    
        TouchableWrapper mTouchView;
    
        public CustomMap_Fragment() {
            super();
        }
    
        public static CustomMap_Fragment newInstance() {
            return new CustomMap_Fragment();
        }
    
        @Override
        public View onCreateView(LayoutInflater arg0, ViewGroup arg1, Bundle arg2) {
            View mapView = super.onCreateView(arg0, arg1, arg2);
    
            Fragment fragment = getParentFragment();
            if (fragment != null && fragment instanceof OnMapReadyListener) {
                ((OnMapReadyListener) fragment).onMapReady();
            }
    
            mTouchView = new TouchableWrapper(getActivity());
            mTouchView.addView(mapView);
    
            return mTouchView;
        }
    
        public static interface OnMapReadyListener {
            void onMapReady();
        }
    }
    
  • 在my Map_片段内(最终将位于支持导航抽屉和片段事务以切换视图的活动中的FrameLayout内)

  • 现在,在我刚刚得到映射的同一个片段中,EventBus接收器在接收到“double_tapped_map”时将执行以下操作:

  • 注意:为了完美地实现这一点,您可以在地图上禁用zoomGestures(这意味着您可以
    myMap.getUiSettings().setZoomGesturesEnabled(false)如果你不这样做,你将能够在地图上快速双击,你会看到地图将从中心变远,因为双击的实现与我发布的第一个答案完全相同,即他们从上一次点击时间中减去当前时间,因此在该窗口中,你可以滑入第三次点击并它不会触发事件总线事件,google map将捕获它;因此禁用缩放手势

    但是,你会发现夹入/夹出不再有效,你也必须处理夹入/夹出,我也做了,但还需要1个小时,我还没有时间这样做,但100%我会在我做时更新答案


    提示:优步也禁用了地图上的旋转手势。
    map.getUiSettings().setrotategesturenabled(false);

    我花了大约3天的时间在谷歌上搜索后,找到了完整的解决方案。我的答案由编辑而成

    最后,在您的活动中:

    ....
    <fragment
        android:id="@+id/map"
        class="yourpackage.CustomMapFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
    ...
    
    。。。。
    ...
    

    我已经在Android 4.1(API 16)和后者上进行了测试,它运行良好且平滑。(关于API<16,我没有任何设备要测试)。

    您可以使用LatLngBounds限制地图从您想要的位置移动。(您可以将边界的东北角和西南角设置为同一点)

    请查看下面的链接


    我也有同样的要求。我必须了解android如何处理事件来解决这个问题,因为我们必须拦截用于缩放的触摸事件,并将滚动事件传递给地图。 为了实现这一点,我们需要一个自定义视图而不是谷歌地图视图。我们的自定义视图截取触摸事件,并决定是不给底层地图一个机会来处理后续事件,还是让底层地图自己来处理所有事件

    现在是编码时间- 这里我们需要两样东西——一个自定义片段,一个自定义视图

  • 自定义片段

    public class CustomMapFragment extends SupportMapFragment implements OnMapReadyCallback {
    
    public View mapView = null;
    
    public WrapperView wrapperView = null;
    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
        mapView = super.onCreateView(inflater, parent, savedInstanceState);
        wrapperView = new WrapperView(getActivity());
        wrapperView.addView(mapView);
        SupportMapFragment mapFragment = (SupportMapFragment) getActivity().getSupportFragmentManager().findFragmentById(R.id.map);
        mapFragment.getMapAsync(this);
        return wrapperView;
    }
    
    @Override
    public View getView() {
        return mapView;
    }
    
    @Override
    public void onMapReady(GoogleMap googleMap) {
        wrapperView.setGoogleMap(googleMap);
    }
    
  • 自定义视图

    public class WrapperView extends FrameLayout {
    
    private GoogleMap googleMap;
    
    Activity activity = null;
    
    ScaleGestureDetector scaleGestureDetector;
    
    public WrapperView(Activity activity) {
        super(activity);
        this.activity=activity;
        scaleGestureDetector = new ScaleGestureDetector(activity ,new MyOnScaleGestureListener());
    }
    
    public void setGoogleMap(GoogleMap map){
        googleMap = map;
    }
    
    private boolean isZoomInProgress(MotionEvent event){
        if(event.getPointerCount()>1){
            return true;
        }
        return false;
    }
    
    @Override
    public boolean onInterceptTouchEvent(MotionEvent event){
        return isZoomInProgress(event);
    }
    
    @Override
    public boolean onTouchEvent(MotionEvent event){
        return scaleGestureDetector.onTouchEvent(event);
    }
    
    public class MyOnScaleGestureListener extends
            ScaleGestureDetector.SimpleOnScaleGestureListener {
    
        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            float previousSpan = detector.getPreviousSpan();
            float currentSpan = detector.getCurrentSpan();
            float targetSpan;
            if(previousSpan>currentSpan){
                targetSpan = previousSpan-currentSpan;
            }else{
                targetSpan = currentSpan-previousSpan;
            }
            float scaleFactor = detector.getScaleFactor();
            if (scaleFactor > 1) {
                if(googleMap.getCameraPosition().zoom!=googleMap.getMaxZoomLevel()) {
                    for(int j=0;j<(targetSpan*2);j++){
                        googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(googleMap.getCameraPosition().target, googleMap.getCameraPosition().zoom + 0.002f));
                    }
                }
            } else {
                if (googleMap.getCameraPosition().zoom != googleMap.getMinZoomLevel()) {
                    for(int j=0;j<(targetSpan*2);j++){
                        googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(googleMap.getCameraPosition().target, googleMap.getCameraPosition().zoom - 0.002f));
                    }
                }
            }
            return true;
        }
    
        @Override
        public boolean onScaleBegin(ScaleGestureDetector detector) {
            return true;
        }
    
        @Override
        public void onScaleEnd(ScaleGestureDetector detector) {}
    }
    
    public类WrapperView扩展了FrameLayout{
    私人谷歌地图谷歌地图;
    活动=空;
    scalegestruedetector scalegestruedetector;
    公共包装器视图(活动){
    超级(活动);
    这个。活动=活动;
    scalegestruedetector=新的scalegestruedetector(活动,新的MyOnScaleGestureListener());
    }
    公共无效设置谷歌地图(谷歌地图){
    谷歌地图=地图;
    }
    私有布尔值isZoomInProgress(运动事件){
    if(event.getPointerCount()>1){
    返回true;
    }
    返回false;
    }
    @凌驾
    公共布尔值onInterceptTouchEvent(MotionEvent){
    返回isZoomInProgress(事件);
    }
    @凌驾
    公共布尔onTouchEvent(运动事件){
    返回scalegestruedetector.onTouchEvent(事件);
    }
    公共类MyOnScaleGestureListener扩展
    ScaleGetStureDetector.SimpleOnScaleGetStureListener{
    @凌驾
    公共布尔标度(scalegestruedetector检测器){
    float previousSpan=检测器。getPreviousSpan();
    float currentSpan=检测器。getCurrentSpan();
    浮动目标跨度;
    如果(以前的span>currentSpan){
    targetSpan=上一个SPAN currentSpan;
    }否则{
    targetSpan=当前span前一span;
    }
    float scaleFactor=detector.getScaleFactor();
    如果(缩放因子>1){
    if(googleMap.getCameraPosition().zoom!=googleMap.getMaxZoomLevel()){
    
    对于(int j=0;j谢谢你的回答。是的,这就是我想我需要做的。我尝试了一些像你说的那样进行重新定心的黑客方法。你完全正确,超级强基。哈坎,你可以添加更多细节。我在我的活动中添加了地图。使用,我想在其中添加上述功能。我最近以更好的方式解决了这个问题y、 我将编辑我的答案以反映所有这些更改,但我今天不能。不幸的是,Yok。如果您能提供帮助,这将是很好的。我现在陷入了这一点:)谢谢。@Odaym。如果我将得到任何新的更新,我将把它放在您的编辑中并进行说明。它现在正在工作:)谢谢帮助,
    public class CustomMapFragment extends Fragment {
    
            CustomMapView view;
            Bundle bundle;
            GoogleMap map;
    
            @Override
            public void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                bundle = savedInstanceState;
            }
    
            @Override
            public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
                View v = inflater.inflate(R.layout.fragment_map, container, false);
    
                view = (CustomMapView) v.findViewById(R.id.mapView);
                view.onCreate(bundle);
                view.onResume();
    
                map = view.getMap();
                view.init(map);
    
                MapsInitializer.initialize(getActivity());
    
                return v;
            }
    
            public GoogleMap getMap() {
                return map;
            }
    
            @Override
            public void onResume() {
                super.onResume();
                view.onResume();
            }
    
            @Override
            public void onPause() {
                super.onPause();
                view.onPause();
            }
    
            @Override
            public void onDestroy() {
                super.onDestroy();
                view.onDestroy();
            }
    
            @Override
            public void onLowMemory() {
                super.onLowMemory();
                view.onLowMemory();
            }
        }
    
    ....
    <fragment
        android:id="@+id/map"
        class="yourpackage.CustomMapFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
    ...
    
    public class CustomMapFragment extends SupportMapFragment implements OnMapReadyCallback {
    
    public View mapView = null;
    
    public WrapperView wrapperView = null;
    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
        mapView = super.onCreateView(inflater, parent, savedInstanceState);
        wrapperView = new WrapperView(getActivity());
        wrapperView.addView(mapView);
        SupportMapFragment mapFragment = (SupportMapFragment) getActivity().getSupportFragmentManager().findFragmentById(R.id.map);
        mapFragment.getMapAsync(this);
        return wrapperView;
    }
    
    @Override
    public View getView() {
        return mapView;
    }
    
    @Override
    public void onMapReady(GoogleMap googleMap) {
        wrapperView.setGoogleMap(googleMap);
    }
    
    public class WrapperView extends FrameLayout {
    
    private GoogleMap googleMap;
    
    Activity activity = null;
    
    ScaleGestureDetector scaleGestureDetector;
    
    public WrapperView(Activity activity) {
        super(activity);
        this.activity=activity;
        scaleGestureDetector = new ScaleGestureDetector(activity ,new MyOnScaleGestureListener());
    }
    
    public void setGoogleMap(GoogleMap map){
        googleMap = map;
    }
    
    private boolean isZoomInProgress(MotionEvent event){
        if(event.getPointerCount()>1){
            return true;
        }
        return false;
    }
    
    @Override
    public boolean onInterceptTouchEvent(MotionEvent event){
        return isZoomInProgress(event);
    }
    
    @Override
    public boolean onTouchEvent(MotionEvent event){
        return scaleGestureDetector.onTouchEvent(event);
    }
    
    public class MyOnScaleGestureListener extends
            ScaleGestureDetector.SimpleOnScaleGestureListener {
    
        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            float previousSpan = detector.getPreviousSpan();
            float currentSpan = detector.getCurrentSpan();
            float targetSpan;
            if(previousSpan>currentSpan){
                targetSpan = previousSpan-currentSpan;
            }else{
                targetSpan = currentSpan-previousSpan;
            }
            float scaleFactor = detector.getScaleFactor();
            if (scaleFactor > 1) {
                if(googleMap.getCameraPosition().zoom!=googleMap.getMaxZoomLevel()) {
                    for(int j=0;j<(targetSpan*2);j++){
                        googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(googleMap.getCameraPosition().target, googleMap.getCameraPosition().zoom + 0.002f));
                    }
                }
            } else {
                if (googleMap.getCameraPosition().zoom != googleMap.getMinZoomLevel()) {
                    for(int j=0;j<(targetSpan*2);j++){
                        googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(googleMap.getCameraPosition().target, googleMap.getCameraPosition().zoom - 0.002f));
                    }
                }
            }
            return true;
        }
    
        @Override
        public boolean onScaleBegin(ScaleGestureDetector detector) {
            return true;
        }
    
        @Override
        public void onScaleEnd(ScaleGestureDetector detector) {}
    }
    
     <fragment xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:map="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/map"
        android:name="yourpackage.CustomMapFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity" />