通过包装器居中缩放 Google 地图?
Centered zooming a Google Map through a wrapper?
我如何在地图上方的透明 ImageView 上设置侦听器,使其仅对上面的捏合(缩放)事件做出反应,而移动地图等其他所有内容都由 Google 地图处理?
我的目标是在地图上创建居中缩放,可以这样做:
mGoogleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(mGoogleMap.getCameraPosition().target, amountOfZoomNeeded));
但我需要先捕获那个捏合事件,并且只有那个事件,因为使用下面的地图的 onTouch 块。
编辑:
我设法使用 ScaleGestureDetectors onScale() 方法创建居中缩放:
public class PinchListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
private GoogleMap googleMap;
public PinchListener(GoogleMap googleMap){
this.googleMap = googleMap;
}
@Override
public boolean onScale(ScaleGestureDetector detector) {
double zoom = googleMap.getCameraPosition().zoom;
zoom = zoom + Math.log(detector.getScaleFactor()) / Math.log(1.5d);
CameraUpdate update = CameraUpdateFactory.newLatLngZoom(googleMap.getCameraPosition().target, (float) zoom);
googleMap.moveCamera(update);
return true;
}
}
然后在我的 MainActivity 中初始化它,其中 mMapWrapper 是我之前提到的透明 ImageView 包装器。
ScaleGestureDetector mScaleGestureDetector = new ScaleGestureDetector(this, new PinchListener(mGoogleMap));
mMapWrapper.setOnTouchListener(new View.OnTouchListener(){
@Override
public boolean onTouch(View v, MotionEvent event) {
mScaleGestureDetector.onTouchEvent(event);
return true;
}
});
但现在我遇到了无法移动地图的问题,因为所有触摸事件都被包装器的 onTouch() 方法占用。我怎样才能防止这种情况发生?
这就是我设法做到这一点的方法。
我创建了两个 类 来检测某些事件,例如猛击、双击、滚动(拖动)和缩放(缩放):
public class PinchListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
private GoogleMap mGoogleMap;
public PinchListener(GoogleMap googleMap) {
this.mGoogleMap = googleMap;
}
@Override
public boolean onScale(ScaleGestureDetector detector) {
double zoom = mGoogleMap.getCameraPosition().zoom;
zoom = zoom + Math.log(detector.getScaleFactor()) / Math.log(1.5d);
CameraUpdate update = CameraUpdateFactory.newLatLngZoom(mGoogleMap.getCameraPosition().target, (float) zoom);
mGoogleMap.moveCamera(update);
return true;
}
}
public class GestureListener extends GestureDetector.SimpleOnGestureListener {
private GoogleMap mGoogleMap;
private boolean mIsInAnimation;
public GestureListener(GoogleMap googleMap) {
this.mGoogleMap = googleMap;
mIsInAnimation = false;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
LatLng target = mGoogleMap.getCameraPosition().target;
Point screenPoint = mGoogleMap.getProjection().toScreenLocation(target);
Point newPoint = new Point(screenPoint.x + (int) distanceX, screenPoint.y + (int) distanceY);
LatLng mapNewTarget = mGoogleMap.getProjection().fromScreenLocation(newPoint);
CameraUpdate update = CameraUpdateFactory.newLatLngZoom(
mapNewTarget, mGoogleMap.getCameraPosition().zoom);
mGoogleMap.moveCamera(update);
return true;
}
@Override
public boolean onDoubleTap(MotionEvent e) {
mGoogleMap.animateCamera(CameraUpdateFactory.zoomIn(), 400, null);
return true;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
if (mIsInAnimation) return false;
int velocity = (int) Math.sqrt(velocityX * velocityX + velocityY * velocityY);
if (velocity < 500) return false;
double k1 = 0.002d; /*exipemental*/
double k2 = 0.002d;/*exipemental*/
LatLng target = mGoogleMap.getCameraPosition().target;
Point screenPoint = mGoogleMap.getProjection().toScreenLocation(target);
Point newPoint = new Point(screenPoint.x - (int) (velocityX * k1),
screenPoint.y - (int) (velocityY * k1));
LatLng mapNewTarget = mGoogleMap.getProjection().fromScreenLocation(newPoint);
CameraUpdate update = CameraUpdateFactory.newLatLngZoom(
mapNewTarget, mGoogleMap.getCameraPosition().zoom);
tryUpdateCamera(update, (int) (velocity * k2));
return true;
}
private void tryUpdateCamera(CameraUpdate update, int animateTime) {
mIsInAnimation = true;
mGoogleMap.animateCamera(update, animateTime, new GoogleMap.CancelableCallback() {
@Override
public void onFinish() {
mIsInAnimation = false;
}
@Override
public void onCancel() {
mIsInAnimation = false;
}
});
}
}
然后我在我的 MainActivity 中初始化了一个 GestureDetector 和 ScaleGestureDetector:
ScaleGestureDetector mScaleGestureDetector = new ScaleGestureDetector(this, new PinchListener(mMap));
GestureDetector mGestureDetector = new GestureDetector(this, new GestureListener(mMap));
我已经在 activity_main 中创建了一个透明图像包装器来检测所有这些事件,然后在下面的 Google 地图上模拟它们,如下所示:
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:id="@+id/map"/>
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/mapWrapper"
/>
最后在我的 MainActivity 中,我为包装器创建了一个 OnTouchListener:
mMapWrapper = findViewById(R.id.mapWrapper);
mMapWrapper.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
mMode = Mode.DRAG;
mGestureDetector.onTouchEvent(event);
mScaleGestureDetector.onTouchEvent(event);
break;
case MotionEvent.ACTION_POINTER_DOWN:
mMode = Mode.ZOOM;
mScaleGestureDetector.onTouchEvent(event);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mMode = Mode.NONE;
mGestureDetector.onTouchEvent(event);
break;
case MotionEvent.ACTION_MOVE:
if (mMode == Mode.DRAG) {
mGestureDetector.onTouchEvent(event);
} else if (mMode == Mode.ZOOM) {
mScaleGestureDetector.onTouchEvent(event);
}
break;
}
return true;
}
});
在最后一步中,我 "feed" 正确的检测器是我想要的事件。如果我没有这样做,缩放将不会完全居中,因为有时会调用 onScroll(Drag) 事件并移动地图。
我如何在地图上方的透明 ImageView 上设置侦听器,使其仅对上面的捏合(缩放)事件做出反应,而移动地图等其他所有内容都由 Google 地图处理?
我的目标是在地图上创建居中缩放,可以这样做:
mGoogleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(mGoogleMap.getCameraPosition().target, amountOfZoomNeeded));
但我需要先捕获那个捏合事件,并且只有那个事件,因为使用下面的地图的 onTouch 块。
编辑:
我设法使用 ScaleGestureDetectors onScale() 方法创建居中缩放:
public class PinchListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
private GoogleMap googleMap;
public PinchListener(GoogleMap googleMap){
this.googleMap = googleMap;
}
@Override
public boolean onScale(ScaleGestureDetector detector) {
double zoom = googleMap.getCameraPosition().zoom;
zoom = zoom + Math.log(detector.getScaleFactor()) / Math.log(1.5d);
CameraUpdate update = CameraUpdateFactory.newLatLngZoom(googleMap.getCameraPosition().target, (float) zoom);
googleMap.moveCamera(update);
return true;
}
}
然后在我的 MainActivity 中初始化它,其中 mMapWrapper 是我之前提到的透明 ImageView 包装器。
ScaleGestureDetector mScaleGestureDetector = new ScaleGestureDetector(this, new PinchListener(mGoogleMap));
mMapWrapper.setOnTouchListener(new View.OnTouchListener(){
@Override
public boolean onTouch(View v, MotionEvent event) {
mScaleGestureDetector.onTouchEvent(event);
return true;
}
});
但现在我遇到了无法移动地图的问题,因为所有触摸事件都被包装器的 onTouch() 方法占用。我怎样才能防止这种情况发生?
这就是我设法做到这一点的方法。
我创建了两个 类 来检测某些事件,例如猛击、双击、滚动(拖动)和缩放(缩放):
public class PinchListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
private GoogleMap mGoogleMap;
public PinchListener(GoogleMap googleMap) {
this.mGoogleMap = googleMap;
}
@Override
public boolean onScale(ScaleGestureDetector detector) {
double zoom = mGoogleMap.getCameraPosition().zoom;
zoom = zoom + Math.log(detector.getScaleFactor()) / Math.log(1.5d);
CameraUpdate update = CameraUpdateFactory.newLatLngZoom(mGoogleMap.getCameraPosition().target, (float) zoom);
mGoogleMap.moveCamera(update);
return true;
}
}
public class GestureListener extends GestureDetector.SimpleOnGestureListener {
private GoogleMap mGoogleMap;
private boolean mIsInAnimation;
public GestureListener(GoogleMap googleMap) {
this.mGoogleMap = googleMap;
mIsInAnimation = false;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
LatLng target = mGoogleMap.getCameraPosition().target;
Point screenPoint = mGoogleMap.getProjection().toScreenLocation(target);
Point newPoint = new Point(screenPoint.x + (int) distanceX, screenPoint.y + (int) distanceY);
LatLng mapNewTarget = mGoogleMap.getProjection().fromScreenLocation(newPoint);
CameraUpdate update = CameraUpdateFactory.newLatLngZoom(
mapNewTarget, mGoogleMap.getCameraPosition().zoom);
mGoogleMap.moveCamera(update);
return true;
}
@Override
public boolean onDoubleTap(MotionEvent e) {
mGoogleMap.animateCamera(CameraUpdateFactory.zoomIn(), 400, null);
return true;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
if (mIsInAnimation) return false;
int velocity = (int) Math.sqrt(velocityX * velocityX + velocityY * velocityY);
if (velocity < 500) return false;
double k1 = 0.002d; /*exipemental*/
double k2 = 0.002d;/*exipemental*/
LatLng target = mGoogleMap.getCameraPosition().target;
Point screenPoint = mGoogleMap.getProjection().toScreenLocation(target);
Point newPoint = new Point(screenPoint.x - (int) (velocityX * k1),
screenPoint.y - (int) (velocityY * k1));
LatLng mapNewTarget = mGoogleMap.getProjection().fromScreenLocation(newPoint);
CameraUpdate update = CameraUpdateFactory.newLatLngZoom(
mapNewTarget, mGoogleMap.getCameraPosition().zoom);
tryUpdateCamera(update, (int) (velocity * k2));
return true;
}
private void tryUpdateCamera(CameraUpdate update, int animateTime) {
mIsInAnimation = true;
mGoogleMap.animateCamera(update, animateTime, new GoogleMap.CancelableCallback() {
@Override
public void onFinish() {
mIsInAnimation = false;
}
@Override
public void onCancel() {
mIsInAnimation = false;
}
});
}
}
然后我在我的 MainActivity 中初始化了一个 GestureDetector 和 ScaleGestureDetector:
ScaleGestureDetector mScaleGestureDetector = new ScaleGestureDetector(this, new PinchListener(mMap));
GestureDetector mGestureDetector = new GestureDetector(this, new GestureListener(mMap));
我已经在 activity_main 中创建了一个透明图像包装器来检测所有这些事件,然后在下面的 Google 地图上模拟它们,如下所示:
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:id="@+id/map"/>
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/mapWrapper"
/>
最后在我的 MainActivity 中,我为包装器创建了一个 OnTouchListener:
mMapWrapper = findViewById(R.id.mapWrapper);
mMapWrapper.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
mMode = Mode.DRAG;
mGestureDetector.onTouchEvent(event);
mScaleGestureDetector.onTouchEvent(event);
break;
case MotionEvent.ACTION_POINTER_DOWN:
mMode = Mode.ZOOM;
mScaleGestureDetector.onTouchEvent(event);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mMode = Mode.NONE;
mGestureDetector.onTouchEvent(event);
break;
case MotionEvent.ACTION_MOVE:
if (mMode == Mode.DRAG) {
mGestureDetector.onTouchEvent(event);
} else if (mMode == Mode.ZOOM) {
mScaleGestureDetector.onTouchEvent(event);
}
break;
}
return true;
}
});
在最后一步中,我 "feed" 正确的检测器是我想要的事件。如果我没有这样做,缩放将不会完全居中,因为有时会调用 onScroll(Drag) 事件并移动地图。