无论你在哪里捏缩放android,都要保持地图居中

我正在寻找类似于优步处理捏缩放事件的方式。 无论您在屏幕上捏什么,它都会使地图居中并放大中心位置。 有没有办法在地图片段上没有某种叠加的情况下做到这一点? 或者我应该只禁用地图的事件,在地图片段上创建叠加层,并处理叠加层中的所有缩放/其他事件?

我花了大约3天的时间在google上搜索后,我已经建立了完整的解决方案。 我的答案是从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); } } } 

并自定义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(); } } 

最后,在您的活动中:

 ....  ... 

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

这是MechEthan想到的代码。

  1. 首先,您必须在叠加视图上检测到双击。

     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); } } 
  2. 无论您在哪里抓取mapView,都要将mapView包装在上面创建的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(); } } 
  3. 在我的Map_Fragment中(最终将位于支持导航抽屉和片段事务以切换视图的活动中的FrameLayout内)

     mMapFragment = CustomMap_Fragment.newInstance(); getChildFragmentManager().beginTransaction().replace(R.id.map_container, mMapFragment).commit(); 
  4. 现在终于在我刚拿到地图的同一片段中,EventBus接收器在收到“double_tapped_map”时会执行以下操作:

     @Subscribe public void eventBus_ListenerMethod(AnswerAvailableEvent event) { //Construct a CameraUpdate object that will zoom into the exact middle of the map, with a zoom of currentCameraZoom + 1 unit zoomInUpdate = CameraUpdateFactory.zoomIn(); //Run that with a speed of 400 ms. map.animateCamera(zoomInUpdate, 400, null); } 

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

但是,你会看到捏合/熄灭将不再起作用,你也必须处理捏,我也已经完成了但是还需要1个小时而我还没有时间去做但是100%我当我这样做时会更新答案。

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

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

google-maps v2 API没有任何明确的自定义缩放处理function。 虽然我确信你可以注入一些东西,但是使用叠加方法可以使你免受google-maps更改的影响,并且如果需要,可以让你更轻松地支持其他地图提供者。

(只是为了完整性:您还可以处理相机后更改事件并重新居中,但这将是一个糟糕的,糟糕的用户体验。)

您可以使用LatLngBounds限制地图从您想要的位置移动。 (你可以设置绑定的东北角和西南角都是相同的点)。

请检查以下链接。

https://developers.google.com/maps/documentation/android-api/views

使用您的GoogleMap对象的setLatLngBoundsForCameraTarget()方法可以轻松实现这一点。 在Google Maps SDK for Android的“相机和视图”页面中:

 private GoogleMap mMap; // Create a LatLngBounds that includes the city of Adelaide in Australia. private LatLngBounds ADELAIDE = new LatLngBounds( new LatLng(-35.0, 138.58), new LatLng(-34.9, 138.61)); // Constrain the camera target to the Adelaide bounds. mMap.setLatLngBoundsForCameraTarget(ADELAIDE);` 

相信我,如果将LatLngBounds放置在标记的确切坐标上,这可以使相机保持在标记的中心位置。 简单!