如何使用Google Maps for Android V2处理地图移动结束?
我想在地图中心更改后立即对地址进行地理编码如何使用Google Maps for Android V2处理地图移动结束?,android,google-maps,android-mapview,google-maps-android-api-2,Android,Google Maps,Android Mapview,Google Maps Android Api 2,我想在地图中心更改后立即对地址进行地理编码 我如何使用新的Android V2谷歌地图处理地图移动端?(我在谈论这个案例,然后用户用手指拖动地图)我会尝试一个。每次摄影机移动完成时,都会调用侦听器。侦听器还将为您提供新位置。在我的测试中,在拖动过程中经常调用侦听器,也许有更好的解决方案。以下是确定拖动开始和拖动结束事件的可能解决方法: 您必须扩展SupportMapFragment或MapFragment。在onCreateView中,您必须将地图视图包装在自定义的框架布局中(在下面的示例中,它
我如何使用新的Android V2谷歌地图处理地图移动端?(我在谈论这个案例,然后用户用手指拖动地图)我会尝试一个。每次摄影机移动完成时,都会调用侦听器。侦听器还将为您提供新位置。在我的测试中,在拖动过程中经常调用侦听器,也许有更好的解决方案。以下是确定拖动开始和拖动结束事件的可能解决方法: 您必须扩展SupportMapFragment或MapFragment。在onCreateView中,您必须将地图视图包装在自定义的框架布局中(在下面的示例中,它是“TouchableWrapper”类),在该类中,您可以截取触摸事件并识别地图是否被点击。如果调用了“onCameraChange”,只需检查是否按下了地图视图(在下面的示例中,这是变量“mMapIsTouched”) 示例代码: 更新1:
- 返回在getView()中创建的原始视图
- 使用dispatchTouchEvent()而不是onInterceptTouchEvent()
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;
}
在相机更改回调方法中:
private final OnCameraChangeListener mOnCameraChangeListener =
new OnCameraChangeListener() {
@Override
public void onCameraChange(CameraPosition cameraPosition) {
if (!mMapIsTouched) {
refreshClustering(false);
}
}
};
过时的改用新的地图API。请参阅朋克斯塔的答案 在使用了上面AZ13的解决方案之后,遇到了评论中提到的问题,我创建了以下解决方案,它更可靠地解决了问题。但是,由于我在onRelease事件之后使用计时器来确定贴图是否仍在动画中,因此此解决方案中有一点延迟 可通过以下链接在Github上找到代码: 我的解决方案可通过以下方式从活动中使用:
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
}
};
我认为地图中的onclick事件是:map.setonmaclick。。。
但是事件拖动是:map.onCameraChangeListener,因为我在这两个函数中调用了log.e,它显示为onClick视图和onDrag视图。因此,只需为您使用它们。从play services maps 9.4.0开始,您可以简单地使用
GoogleMap.OnCameraMoveStartedListener
、GoogleMap.OnCameraMoveListener
和GoogleMap.onCameradleListener
如果出于某种原因,您希望使用现在已弃用的旧API,则可以使用onCamerachenglistener
。但你必须意识到两件事:
onCameraChange()
可能会被多次调用,或者仅被调用一次(当拖动停止时)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);
}
});
}
基于Tobus answer的Xamarin Android中具有处理程序内部类的增强解决方案:
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
}
}
}
}
}
查看新的地图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();
}
只要用户拖动地图,我就必须将标记设置为中心动画。我已经用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);
}
}
}
});
}
}
活动\u映射\u拖动\u侦听器.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>
<?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">
<Button
android:id="@+id/btn_select_place"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Select Place" />
<FrameLayout
android:id="@+id/frame_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
最简单的方法是使用SetOnCameraideListener方法来处理地图片段上触摸侦听器的移动结束状态。 请参见下面的示例:
mMap.setOnCameraMoveStartedListener(new GoogleMap.OnCameraMoveStartedListener() {
@Override
public void onCameraMoveStarted(int i) {
mapPin.startAnimation(animZoomOut);
}
});
mMap.setOnCameraIdleListener(new GoogleMap.OnCameraIdleListener() {
@Override
public void onCameraIdle() {
mapPin.startAnimation(animZoomIn);
}
});
onTouchEvent方法对你没有帮助?谷歌仍然没有这个内置的!疯狂..我发现了那个方法,但正如你说的,它经常开火。我只需要在用户停止拖动地图并将手指移开时进行地理编码。所以我似乎也需要自己来处理触摸。但是在新的地图api中没有onTouch处理程序。@AlexeyZakharov是对的,它被触发太频繁,导致动画被卡住。AZ13的答案非常好。嘿@Alexey Zakharov,请查看Google地图问题跟踪器上的线程:这是真的。不能保证在您确定ACTION\u UP事件后调用onCameraChanged()。无论如何,我也希望谷歌能尽快解决这个问题@AZ13我得到错误“类型MyMapFragment的getActivity()方法未定义”。你是如何声明MyMapFragment的?@AZ13我检查了你的实现,必须承认该事件仍然没有在每个地图移动中触发。查看.Nice,但实际上您不需要实现定制的框架布局,只需执行
setOnTouchListener(newview.OnTouchListener())…
在framelayout上,其中包含事件处理代码。此问题被标记为低质量,因为如果其长度和内容不正确。您能否添加一个解释,说明这是如何解决问题的,或者引用所使用的函数?对我来说似乎很好,这是对@Az13解决方案的一个很好的增强:)@Mads Frandsen,您可以分享如何将您的库与Marker setOnMarkerClickListener结合起来吗?我尝试使用您的库,当按下任何标记时,代码将始终在apsetled上执行fuction@simeh是的,我认为任何接触都将被视为未解决。在将其设置为“未结算”之前,您可能会检查是否有任何移动,这样可以避免只需单击一下就可以进行onMapsetled调用。如果您当时还没有解决问题,我可能会在这个周末或下个周末浏览我的(旧)代码。@Mads Frandsen,我将这个库与另一个检测单触的代码片段结合起来,设法解决了这个问题。谢谢你的回复,但是如果你能把它上传到Maven或者像jitpack.io一样,这样我们就可以在gradle上使用它了。完美的解决方案!
<?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">
<Button
android:id="@+id/btn_select_place"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Select Place" />
<FrameLayout
android:id="@+id/frame_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
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.
}
});
mMap.setOnCameraMoveStartedListener(new GoogleMap.OnCameraMoveStartedListener() {
@Override
public void onCameraMoveStarted(int i) {
mapPin.startAnimation(animZoomOut);
}
});
mMap.setOnCameraIdleListener(new GoogleMap.OnCameraIdleListener() {
@Override
public void onCameraIdle() {
mapPin.startAnimation(animZoomIn);
}
});