如何使用Google Maps for Android V2处理地图移动结束?

我想在地图中心更改后立即对地址进行地址parsing。

如何使用Google Maps for Android V2处理地图移动? (我正在谈论的情况下,然后用户通过手指拖动地图)

以下是确定拖动开始和拖动结束事件的可能的解决方法:

您必须扩展SupportMapFragment或MapFragment。 在onCreateView中,您必须将自己的MapView封装在自定义的FrameLayout中(在下面的示例中是“TouchableWrapper”类),在该对话框中,您可以截取触摸事件并识别地图是否被轻敲。 如果您的“onCameraChange”被调用,只要检查是否按下地图视图(在下面的例子中是variables“mMapIsTouched”)。

示例代码:

更新1:

  • 在getView()中返回原创视图
  • 使用dispatchTouchEvent()而不是onInterceptTouchEvent()

自定义FrameLayout:

private class TouchableWrapper extends FrameLayout { @Override public boolean dispatchTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: mMapIsTouched = true; break; case MotionEvent.ACTION_UP: mMapIsTouched = false; break; } return super.dispatchTouchEvent(ev); } } 

在你自定义的MapFragment中:

 @Override public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) { mOriginalContentView = super.onCreateView(inflater, parent, savedInstanceState); mTouchView = new TouchableWrapper(getActivity()); mTouchView.addView(mOriginalContentView); return mTouchView; } @Override public View getView() { return mOriginalContentView; } 

在你的相机改变callback方法:

 private final OnCameraChangeListener mOnCameraChangeListener = new OnCameraChangeListener() { @Override public void onCameraChange(CameraPosition cameraPosition) { if (!mMapIsTouched) { refreshClustering(false); } } }; 

看看新的地图api。

  @Override public void onMapReady(GoogleMap map) { mMap = map; mMap.setOnCameraIdleListener(this); mMap.setOnCameraMoveStartedListener(this); mMap.setOnCameraMoveListener(this); mMap.setOnCameraMoveCanceledListener(this); // Show Sydney on the map. mMap.moveCamera(CameraUpdateFactory .newLatLngZoom(new LatLng(-33.87365, 151.20689), 10)); } @Override public void onCameraMoveStarted(int reason) { if (reason == OnCameraMoveStartedListener.REASON_GESTURE) { Toast.makeText(this, "The user gestured on the map.", Toast.LENGTH_SHORT).show(); } else if (reason == OnCameraMoveStartedListener .REASON_API_ANIMATION) { Toast.makeText(this, "The user tapped something on the map.", Toast.LENGTH_SHORT).show(); } else if (reason == OnCameraMoveStartedListener .REASON_DEVELOPER_ANIMATION) { Toast.makeText(this, "The app moved the camera.", Toast.LENGTH_SHORT).show(); } } @Override public void onCameraMove() { Toast.makeText(this, "The camera is moving.", Toast.LENGTH_SHORT).show(); } @Override public void onCameraMoveCanceled() { Toast.makeText(this, "Camera movement canceled.", Toast.LENGTH_SHORT).show(); } @Override public void onCameraIdle() { Toast.makeText(this, "The camera has stopped moving.", Toast.LENGTH_SHORT).show(); } 

developers.google.com示例

在使用上面的AZ13的解决scheme后,遇到了评论中提到的问题,我创build了以下解决scheme,可以更可靠地解决问题。 但是,由于我在onRelease事件之后使用了一个计时器来确定地图是否仍然具有animation效果,所以在此解决scheme中稍有延迟。

代码可以通过以下链接在Github上find: https : //github.com/MadsFrandsen/MapStateListener

我的解决scheme可以通过以下方式从活动中使用:

 new MapStateListener(mMap, mMapFragment, this) { @Override public void onMapTouched() { // Map touched } @Override public void onMapReleased() { // Map released } @Override public void onMapUnsettled() { // Map unsettled } @Override public void onMapSettled() { // Map settled } }; 

我会尝试onCameraChangeListener 。 每当摄像机的移动结束时,都会调用监听器。 听众也会给你新的位置。 在我的testing中,聆听者在拖动过程中经常被调用,也许有更好的解决scheme。

从play-services-maps 9.4.0开始,您可以简单地使用GoogleMap.OnCameraMoveStartedListenerGoogleMap.OnCameraMoveListenerGoogleMap.OnCameraIdleListener

如果出于某种原因想要使用现在不赞成的旧API,则可以使用onCameraChangeListener 。 但是你必须知道两件事情:

  1. onCameraChange()可能会被调用很多次,而拖动地图或只有一次(当拖动停止)。
  2. onCameraChange()的最后一次调用中的相机位置可能与最终的相机位置稍有不同。

以下代码考虑了这两个问题:

 private static final int MESSAGE_ID_SAVE_CAMERA_POSITION = 1; private static final int MESSAGE_ID_READ_CAMERA_POSITION = 2; private CameraPosition lastCameraPosition; private Handler handler; private GoogleMap googleMap; public void onMapReady(GoogleMap theGoogleMap) { googleMap = theGoogleMap; handler = new Handler() { public void handleMessage(Message msg) { if (msg.what == MESSAGE_ID_SAVE_CAMERA_POSITION) { lastCameraPosition = googleMap.getCameraPosition(); } else if (msg.what == MESSAGE_ID_READ_CAMERA_POSITION) { if (lastCameraPosition.equals(googleMap.getCameraPosition())) { Log.d(LOG, "Camera position stable"); } } } }; googleMap.setOnCameraChangeListener(new GoogleMap.OnCameraChangeListener() { @Override public void onCameraChange(CameraPosition cameraPosition) { handler.removeMessages(MESSAGE_ID_SAVE_CAMERA_POSITION); handler.removeMessages(MESSAGE_ID_READ_CAMERA_POSITION); handler.sendEmptyMessageDelayed(MESSAGE_ID_SAVE_CAMERA_POSITION, 300); handler.sendEmptyMessageDelayed(MESSAGE_ID_READ_CAMERA_POSITION, 600); } }); } 

只要用户拖动地图,我必须将我的标记设置为居中。 我用Stas Shakirov的答案来实现它

MapDragListenerFragment.class

 public class MapDragListenerFragment extends Fragment implements OnMapReadyCallback, GoogleMap.OnMapLoadedCallback { private Context mContext; private SupportMapFragment supportMapFragment; private Marker centerMarker; private LatLng mapCenterLatLng; private TextView tvLocationName; private Button btnFinalizeDestination; private GoogleMap mGoogleMap; @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_map_drag_listener, container, false); } @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); mContext = getActivity(); tvLocationName = (TextView) view.findViewById(R.id.tv_location_name); } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); FragmentManager fm = getActivity().getSupportFragmentManager();//getChildFragmentManager();// supportMapFragment = (SupportMapFragment) fm.findFragmentById(R.id.map_container); if (supportMapFragment == null) { //// FIXME: 2/13/2017 crashes at casting to TouchableMapFragment supportMapFragment = SupportMapFragment.newInstance(); fm.beginTransaction().replace(R.id.map_container, supportMapFragment).commit(); } supportMapFragment.getMapAsync(this); } @Override public void onMapReady(GoogleMap googleMap) { if (googleMap != null) { mGoogleMap = googleMap; centerMarker = mGoogleMap.addMarker(new MarkerOptions().position(mGoogleMap.getCameraPosition().target) .title("Center of Map") .icon(BitmapDescriptorFactory.fromResource(R.drawable.end_green))); mGoogleMap.setOnCameraIdleListener(new GoogleMap.OnCameraIdleListener() { @Override public void onCameraIdle() { mapCenterLatLng = mGoogleMap.getCameraPosition().target; animateMarker(centerMarker,mapCenterLatLng,false); Toast.makeText(mContext, "The camera has stopped moving.", Toast.LENGTH_SHORT).show(); String address = getCompleteAddressString(mapCenterLatLng.longitude,mapCenterLatLng.longitude); tvLocationName.setText(address); } }); mGoogleMap.setOnCameraMoveStartedListener(new GoogleMap.OnCameraMoveStartedListener() { @Override public void onCameraMoveStarted(int reason) { if (reason == GoogleMap.OnCameraMoveStartedListener.REASON_GESTURE) { ///tvLocationName.setText("Lat " + mapCenterLatLng.latitude + " Long :" + mapCenterLatLng.longitude); Toast.makeText(mContext, "The user gestured on the map.", Toast.LENGTH_SHORT).show(); } else if (reason == GoogleMap.OnCameraMoveStartedListener .REASON_API_ANIMATION) { Toast.makeText(mContext, "The user tapped something on the map.", Toast.LENGTH_SHORT).show(); } else if (reason == GoogleMap.OnCameraMoveStartedListener .REASON_DEVELOPER_ANIMATION) { Toast.makeText(mContext, "The app moved the camera.", Toast.LENGTH_SHORT).show(); } } }); mGoogleMap.setOnCameraMoveListener(new GoogleMap.OnCameraMoveListener() { @Override public void onCameraMove() { Toast.makeText(mContext, "The camera is moving.", Toast.LENGTH_SHORT).show(); } }); mGoogleMap.setOnCameraMoveCanceledListener(new GoogleMap.OnCameraMoveCanceledListener() { @Override public void onCameraMoveCanceled() { Toast.makeText(mContext, "Camera movement canceled.", Toast.LENGTH_SHORT).show(); } }); mapCenterLatLng = mGoogleMap.getCameraPosition().target;// it should be done on MapLoaded. if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { return; } mGoogleMap.setMyLocationEnabled(true); mGoogleMap.animateCamera(CameraUpdateFactory.zoomTo(15)); mGoogleMap.setOnMapLoadedCallback(this); mGoogleMap.setOnCameraMoveListener(new GoogleMap.OnCameraMoveListener() { @Override public void onCameraMove() { } }); } } public void animateMarker(final Marker marker, final LatLng toPosition, final boolean hideMarker) { final Handler handler = new Handler(); final long start = SystemClock.uptimeMillis(); Projection proj = mGoogleMap.getProjection(); Point startPoint = proj.toScreenLocation(marker.getPosition()); final LatLng startLatLng = proj.fromScreenLocation(startPoint); final long duration = 500; final Interpolator interpolator = new LinearInterpolator(); handler.post(new Runnable() { @Override public void run() { long elapsed = SystemClock.uptimeMillis() - start; float t = interpolator.getInterpolation((float) elapsed / duration); double lng = t * toPosition.longitude + (1 - t) * startLatLng.longitude; double lat = t * toPosition.latitude + (1 - t) * startLatLng.latitude; marker.setPosition(new LatLng(lat, lng)); if (t < 1.0) { // Post again 16ms later. handler.postDelayed(this, 16); } else { if (hideMarker) { marker.setVisible(false); } else { marker.setVisible(true); } } } }); } } 

其中fragment_map_drag_listener.xml

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <RelativeLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"> <fragment android:id="@+id/map_container" android:name="com.google.android.gms.maps.SupportMapFragment" android:layout_width="match_parent" android:layout_height="match_parent" /> <ImageView android:id="@+id/iv_center_overlay" android:layout_width="25dp" android:layout_height="25dp" android:visibility="gone" android:layout_centerInParent="true" android:src="@drawable/start_blue" /> </RelativeLayout> <TextView android:id="@+id/tv_location_name" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="4dp" android:text="Location Name" /> </LinearLayout> 
 @Override public boolean onTouchEvent(MotionEvent event, MapView mapView){ if(event.getAction() == MotionEvent.ACTION_MOVE) return true; return false; } 

我认为在地图上点击的 事件是: map.setOnMapClick …但是事件拖动是: map.onCameraChangeListener,因为我在这两个函数中调用了一个log.e ,并且它显示如onClick视图和onDrag视图。 所以只是为你使用它们。

基于Tobus的Xamarin Android中Handler内部类的增强解决scheme回答:

 public void OnMapReady(GoogleMap googleMap) { _googleMap = googleMap; if (_googleMap != null) { _cameraPositionHandler = new CameraPositionlHandler(_googleMap); _googleMap.CameraChange += OnCameraChanged; } } void OnCameraChanged (object sender, GoogleMap.CameraChangeEventArgs e) { _cameraPositionHandler.RemoveMessages(MESSAGE_ID_SAVE_CAMERA_POSITION); _cameraPositionHandler.RemoveMessages(MESSAGE_ID_READ_CAMERA_POSITION); _cameraPositionHandler.SendEmptyMessageDelayed(MESSAGE_ID_SAVE_CAMERA_POSITION, 300); _cameraPositionHandler.SendEmptyMessageDelayed(MESSAGE_ID_READ_CAMERA_POSITION, 600); } 

随着以下内部类:

  private class CameraPositionlHandler : Handler { private CameraPosition _lastCameraPosition; private GoogleMap _googleMap; public CameraPositionlHandler (GoogleMap googleMap) { _googleMap = googleMap; } public override void HandleMessage(Message msg) { if (_googleMap != null) { if (msg.What == MESSAGE_ID_SAVE_CAMERA_POSITION) { _lastCameraPosition = _googleMap.CameraPosition; } else if (msg.What == MESSAGE_ID_READ_CAMERA_POSITION) { if (_lastCameraPosition.Equals(_googleMap.CameraPosition)) { Console.WriteLine("Camera position stable"); //do what you want } } } } } 

在相机闲置是你现在应该使用的

  googleMap.setOnCameraIdleListener(new GoogleMap.OnCameraIdleListener() { @Override public void onCameraIdle() { //Called when camera movement has ended, there are no pending animations and the user has stopped interacting with the map. } });