Keep map centered regardless of where you pinch zoom on android

前端 未结 5 784
谎友^
谎友^ 2020-12-01 11:10

I\'m looking to do something similar to the way Uber handles pinch zoom events. No matter where you pinch on the screen, it keeps the map centered and zooms in on the center

5条回答
  •  刺人心
    刺人心 (楼主)
    2020-12-01 11:48

    I've founded complete solution after spending about 3 days to search on google. My answer is edited from https://stackoverflow.com/a/32734436/3693334.

    public class CustomMapView extends MapView {
    
        private int fingers = 0;
        private GoogleMap googleMap;
        private long lastZoomTime = 0;
        private float lastSpan = -1;
        private Handler handler = new Handler();
    
        private ScaleGestureDetector scaleGestureDetector;
        private GestureDetector gestureDetector;
    
        public CustomMapView(Context context) {
            super(context);
        }
    
        public CustomMapView(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public CustomMapView(Context context, AttributeSet attrs, int style) {
            super(context, attrs, style);
        }
    
        public CustomMapView(Context context, GoogleMapOptions options) {
            super(context, options);
        }
    
        public void init(GoogleMap map) {
            scaleGestureDetector = new ScaleGestureDetector(getContext(), new ScaleGestureDetector.OnScaleGestureListener() {
                @Override
                public boolean onScale(ScaleGestureDetector detector) {
                    if (lastSpan == -1) {
                        lastSpan = detector.getCurrentSpan();
                    } else if (detector.getEventTime() - lastZoomTime >= 50) {
                        lastZoomTime = detector.getEventTime();
                        googleMap.animateCamera(CameraUpdateFactory.zoomBy(getZoomValue(detector.getCurrentSpan(), lastSpan)), 50, null);
                        lastSpan = detector.getCurrentSpan();
                    }
                    return false;
                }
    
                @Override
                public boolean onScaleBegin(ScaleGestureDetector detector) {
                    lastSpan = -1;
                    return true;
                }
    
                @Override
                public void onScaleEnd(ScaleGestureDetector detector) {
                    lastSpan = -1;
    
                }
            });
            gestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() {
                @Override
                public boolean onDoubleTapEvent(MotionEvent e) {
    
                    disableScrolling();
                    googleMap.animateCamera(CameraUpdateFactory.zoomIn(), 400, null);
    
                    return true;
                }
            });
            googleMap = map;
        }
    
        private float getZoomValue(float currentSpan, float lastSpan) {
            double value = (Math.log(currentSpan / lastSpan) / Math.log(1.55d));
            return (float) value;
        }
    
        @Override
        public boolean dispatchTouchEvent(MotionEvent ev) {
            gestureDetector.onTouchEvent(ev);
            switch (ev.getAction() & MotionEvent.ACTION_MASK) {
                case MotionEvent.ACTION_POINTER_DOWN:
                    fingers = fingers + 1;
                    break;
                case MotionEvent.ACTION_POINTER_UP:
                    fingers = fingers - 1;
                    break;
                case MotionEvent.ACTION_UP:
                    fingers = 0;
                    break;
                case MotionEvent.ACTION_DOWN:
                    fingers = 1;
                    break;
            }
            if (fingers > 1) {
                disableScrolling();
            } else if (fingers < 1) {
                enableScrolling();
            }
            if (fingers > 1) {
                return scaleGestureDetector.onTouchEvent(ev);
            } else {
                return super.dispatchTouchEvent(ev);
            }
        }
    
        private void enableScrolling() {
            if (googleMap != null && !googleMap.getUiSettings().isScrollGesturesEnabled()) {
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        googleMap.getUiSettings().setAllGesturesEnabled(true);
                    }
                }, 50);
            }
        }
    
        private void disableScrolling() {
            handler.removeCallbacksAndMessages(null);
            if (googleMap != null && googleMap.getUiSettings().isScrollGesturesEnabled()) {
                googleMap.getUiSettings().setAllGesturesEnabled(false);
            }
        }
    }
    

    and customize MapFragment

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

    Finally, in your activity:

    ....
    
    ...
    

    I've already tested on Android 4.1 (API 16) and latter, it work fine and smooth. (About API < 16, I haven't any device to test).

提交回复
热议问题