我想在地圖中心更改後立即對地址進行地址解析。如何使用Google Maps for Android V2處理地圖移動結束?
如何使用新的Google Maps for Android V2處理地圖移動? (我在談論的情況下,然後用戶通過手指拖動地圖)
我想在地圖中心更改後立即對地址進行地址解析。如何使用Google Maps for Android V2處理地圖移動結束?
如何使用新的Google Maps for Android V2處理地圖移動? (我在談論的情況下,然後用戶通過手指拖動地圖)
這裏是確定拖曳開始和結束拖動事件可能的解決方法:
必須擴展SupportMapFragment或MapFragment。在onCreateView中,您必須將自己的MapView包裝在自定義的FrameLayout中(在下面的示例中,它是「TouchableWrapper」類),您可以在其中攔截觸摸事件並識別是否輕敲地圖。如果您的「onCameraChange」被調用,只需檢查地圖視圖是否被按下(例如下面的例子是變量「mMapIsTouched」)。
示例代碼:
UPDATE 1:在getView
定製的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;
}
在你的相機更改回調方法:
private final OnCameraChangeListener mOnCameraChangeListener =
new OnCameraChangeListener() {
@Override
public void onCameraChange(CameraPosition cameraPosition) {
if (!mMapIsTouched) {
refreshClustering(false);
}
}
};
嘿@Alexey Zakharov,請在Google地圖問題跟蹤器中查看主題:http://code.google.com/p/gmaps-api-issues/issues/detail?id=4636&q=apitype%3DAndroid2&sort=修改後的&colspec = ID%20Type%20Status%20Introduced%20Fixed%20Summary%20Stars%20ApiType%20Internal%20Modified – AZ13
的確如此。不確定在確定ACTION_UP事件後,onCameraChanged()將被調用。無論如何,我也希望Google能很快解決這個問題! – AZ13
非常有幫助的答案,謝謝 –
我會嘗試一個onCameraChangeListener。每次攝像機移動結束時,都會調用監聽器。聽衆也會給你新的位置。在我的測試中,聽者在拖動過程中經常被調用,也許有更好的解決方案。
我發現這種方法,但正如你所說的那樣,它經常發生。我只需要在用戶停止拖動地圖並放開手指時進行地理編碼。因此,我似乎也需要處理自己。但是新地圖API中沒有onTouch處理程序。 –
@AlexeyZakharov是對的,它經常被觸發導致動畫卡住AZ13的答案是一個非常好的答案。 – TypingPanda
使用AZ13的解決方案之上,並跑入在評論中提到的問題後,我創建了以下解決方案,這可以更可靠地解決問題。但是,由於我在onRelease事件之後使用計時器來確定地圖是否仍然具有動畫效果,因此此解決方案中存在一些延遲。
的代碼可以在Github上通過此鏈接找到:https://github.com/MadsFrandsen/MapStateListener
我的解決方案可以從活動以下列方式使用:
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
}
};
似乎爲我工作得很好,它是一個很好的增強@ Az13解決方案:) – Javier
@Mads Frandsen,可能會分享你如何將你的庫與標記setOnMarkerClickListener?我嘗試使用你的庫,當按下任何標記時,代碼將始終在MapSettled功能上執行 –
@simeh是的,我認爲任何觸摸都會被視爲不穩定。您可以在將其設置爲未解決之前檢查是否有任何移動 - 這可以避免onMapSettled調用,只需點擊即可。如果到那時您還沒有解決問題,我可能會在本週末或下一週通過我的(舊)代碼。 –
@Override
public boolean onTouchEvent(MotionEvent event, MapView mapView){
if(event.getAction() == MotionEvent.ACTION_MOVE)
return true;
return false;
}
這個問題被標記爲低質量,因爲如果它的長度和內容。你可以添加一個解釋如何解決這個問題,也許引用使用的功能? – Popnoodles
我認爲事件的onclick在地圖是:map.setOnMapClick ... 但是事件拖動是:map.onCameraChangeListener因爲我在這兩個函數中調用了log.e,並且它顯示如onClick view和onDrag view。所以只是爲你使用它們。
從播放服務地圖開始9.4。0您可以簡單地使用GoogleMap.OnCameraMoveStartedListener
,GoogleMap.OnCameraMoveListener
和GoogleMap.OnCameraIdleListener
。
如果出於某種原因想要使用現在已棄用的舊API,則可以使用onCameraChangeListener
。但您必須注意以下兩件事:
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);
}
});
}
在Xamarin的Android的處理程序內類,基於Tobus答案增強溶液:
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
}
}
}
}
}
查看新的m aps 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();
}
完美的解決方案! – Blablablabli
我有我的動畫標記只要用戶拖動地圖中心。我一直在使用斯塔斯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>
其中 MapDragListenerActivity
實現了它public class MapDragListenerActivity extends AppCompatActivity {
private Context mContext;
private static final String TAG = MapDragListenerFragment.class.getSimpleName();
private MapDragListenerFragment mapDragListenerFragment;
private Button selectPlaceBtn;
public static final int PLACE_AUTOCOMPLETE_REQUEST_CODE = 1219;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map_drag_listener);
mContext = MapDragListenerActivity.this;
mapDragListenerFragment = new MapDragListenerFragment();
getSupportFragmentManager().beginTransaction()
.replace(R.id.frame_container,//where frame_container is a FrameLayout
mapDragListenerFragment,
MapyFragment.class.getSimpleName()).commit();
selectPlaceBtn = (Button) findViewById(R.id.btn_select_place);
selectPlaceBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
Intent intent = new PlaceAutocomplete.IntentBuilder(
PlaceAutocomplete.MODE_FULLSCREEN).build(MapDragListenerActivity.this);
startActivityForResult(intent, PLACE_AUTOCOMPLETE_REQUEST_CODE);
} catch (GooglePlayServicesRepairableException e) {
e.printStackTrace();
} catch (GooglePlayServicesNotAvailableException e) {
e.printStackTrace();
}
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == PLACE_AUTOCOMPLETE_REQUEST_CODE){
if (resultCode == RESULT_OK) {
Place place = PlaceAutocomplete.getPlace(mContext, data);
if(mapDragListenerFragment != null && mapDragListenerFragment.isVisible())
mapDragListenerFragment.updateMarkerAtPosition(
place.getLatLng() ,place.getName().toString());
Log.i(TAG, "Place:" + place.toString());
} else if (resultCode == PlaceAutocomplete.RESULT_ERROR) {
Status status = PlaceAutocomplete.getStatus(mContext, data);
Log.i(TAG, status.getStatusMessage());
} else if (requestCode == RESULT_CANCELED) {
}
}
}
}
activity_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">
<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>
On camera idle is what you should use now
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.
}
});
最簡單的方法是使用setOnCameraIdleListener方法來處理你的地圖片段觸摸監聽你的舉動最終狀態。 請參閱下面的示例:
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方法不幫你嗎? – Yahor10