问题描述
我已经添加了GroundOverlay映射并想限制滚动和在此区域内缩放
I've added GroundOverlay to map and want to limit scrolling and zooming within this area.
如何减少对Android的谷歌地图一定范围内滚动?
How to limit scrolling within some bounds on android google maps?
是否有可能从MapFragment得到瞬间动作点?
Is it possible to get instantly motion points from MapFragment?
请帮我。
推荐答案
可能为时已晚,但这里是我的解决方案:
May be it is too late, but here is my solution:
-
禁用内置的GoogleMap的手势。
Disabled built-in GoogleMap's gestures.
添加自定义手势(用于滚动,一扔和缩放)。
Added custom gestures (for scrolling, fling and scaling).
处理事件时检查允许的区域。
Checking for allowed area when processing events.
设置边界/手动变焦与标准地图的功能。
Set bounds/zoom manually with standard Map's functions.
这里是我的例子:
[增订]
有一个问题 - 当触摸事件:收到地图初始化之前
There was a problem - when touch events were recieved before map was initialized.
在onInterceptTouchEvent检查空值
check null values in onInterceptTouchEvent
另外我发现,我的解决办法是略微慢于内置的功能。
Also I have discovered that my solution is slightly slowly than build-in function.
import android.content.Context;
import android.graphics.Point;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import com.google.android.gms.common.GooglePlayServicesNotAvailableException;
import com.google.android.gms.maps.CameraUpdate;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMapOptions;
import com.google.android.gms.maps.MapView;
import com.google.android.gms.maps.MapsInitializer;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.VisibleRegion;
public class RestrictedMapView extends MapView {
public static float MAX_ZOOM = 20;
public static float MIN_ZOOM = 5;
public static float MIN_ZOOM_FOR_FLING = 7;
public static double MAX_LONGITUDE = 183.61;
public static double MIN_LONGITUDE = 159.31;
public static double MAX_LATITUDE = -32.98;
public static double MIN_LATITUDE = -53.82;
public static double DEF_LATITUDE = -41.78;
public static double DEF_LONGITUDE = 173.02;
public static float DEF_ZOOM = 7;
private Handler mHandler = new Handler();
private Context mContext;
private VisibleRegion mLastCorrectRegion = null;
private boolean mIsInAnimation = false;
public RestrictedMapView(Context c, AttributeSet a, int o) {
super(c, a, o);
init(c);
}
public RestrictedMapView(Context c, AttributeSet a) {
super(c, a);
init(c);
}
public RestrictedMapView(Context c) {
super(c);
init(c);
}
public RestrictedMapView(Context c, GoogleMapOptions o) {
super(c, o);
init(c);
}
private GestureDetector mGestureDetector = null;
private GestureDetector.SimpleOnGestureListener mGestudeListener =
new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
if (mIsInAnimation) return false;
GoogleMap map = getMap();
LatLng target = map.getCameraPosition().target;
Point screenPoint = map.getProjection().toScreenLocation(target);
Point newPoint = new Point(screenPoint.x + (int)distanceX, screenPoint.y + (int)distanceY);
LatLng mapNewTarget = map.getProjection().fromScreenLocation(newPoint);
CameraUpdate update = CameraUpdateFactory.newLatLngZoom(
mapNewTarget,map.getCameraPosition().zoom);
tryUpdateCamera(update, 0);
return true;
}
@Override
public boolean onFling (MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
if (mIsInAnimation) return false;
GoogleMap map = getMap();
double zoom = map.getCameraPosition().zoom;
if (zoom < MIN_ZOOM_FOR_FLING)
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 = map.getCameraPosition().target;
Point screenPoint = map.getProjection().toScreenLocation(target);
Point newPoint = new Point(screenPoint.x - (int)(velocityX * k1 * zoom * zoom/*exipemental*/),
screenPoint.y - (int)(velocityY * k1 * zoom * zoom/*exipemental*/));
LatLng mapNewTarget = map.getProjection().fromScreenLocation(newPoint);
CameraUpdate update = CameraUpdateFactory.newLatLngZoom(
mapNewTarget,map.getCameraPosition().zoom);
tryUpdateCamera(update, (int)(velocity * k2 * zoom * zoom) /*exipemental*/);
return true;
}
};
private ScaleGestureDetector mScaleGestureDetector = null;
private ScaleGestureDetector.SimpleOnScaleGestureListener mScaleGestudeListener =
new ScaleGestureDetector.SimpleOnScaleGestureListener() {
@Override
public boolean onScale (ScaleGestureDetector detector) {
if (mIsInAnimation) return false;
GoogleMap map = getMap();
double zoom = map.getCameraPosition().zoom;
double k = 1d / detector.getScaleFactor();
int x = (int) detector.getFocusX();
int y = (int) detector.getFocusY();
LatLng mapFocus = map.getProjection().
fromScreenLocation(new Point(x, y));
LatLng target = map.getCameraPosition().target;
zoom = zoom + Math.log(detector.getScaleFactor()) / Math.log(2d);
if (zoom < MIN_ZOOM)
if (zoom == MIN_ZOOM) return false;
else zoom = MIN_ZOOM;
if (zoom > MAX_ZOOM)
if (zoom == MAX_ZOOM) return false;
else zoom = MAX_ZOOM;
double dx = norm(mapFocus.longitude) - norm(target.longitude);
double dy = mapFocus.latitude - target.latitude;
double dk = 1d - 1d / k;
LatLng newTarget = new LatLng(target.latitude - dy * dk,
norm(target.longitude) - dx * dk);
CameraUpdate update = CameraUpdateFactory.newLatLngZoom(newTarget, (float) zoom);
tryUpdateCamera(update, 0);
return true;
}
};
private void tryUpdateCamera(CameraUpdate update, int animateTime) {
GoogleMap map = getMap();
final VisibleRegion reg = map.getProjection().getVisibleRegion();
if (animateTime <= 0) {
map.moveCamera(update);
checkCurrentRegion(reg);
} else {
mIsInAnimation = true;
map.animateCamera(update, animateTime, new GoogleMap.CancelableCallback() {
@Override
public void onFinish() {
mIsInAnimation = false;
checkCurrentRegion(reg);
}
@Override
public void onCancel() {
mIsInAnimation = false;
checkCurrentRegion(reg);
}
});
}
}
private void checkCurrentRegion(VisibleRegion oldReg) {
GoogleMap map = getMap();
VisibleRegion regNew = map.getProjection().getVisibleRegion();
if (checkBounds(regNew)) {
mLastCorrectRegion = regNew;
} else {
if (mLastCorrectRegion != null)
oldReg = mLastCorrectRegion;
mIsInAnimation = true;
map.animateCamera(CameraUpdateFactory.newLatLngBounds(
oldReg.latLngBounds, 0),
200, new GoogleMap.CancelableCallback() {
@Override
public void onFinish() {
mIsInAnimation = false;
}
@Override
public void onCancel() {
mIsInAnimation = false;
}
});
}
}
/**
*
*
* @param lonVal
* @return
*/
private double norm(double lonVal) {
while (lonVal > 360d) lonVal -= 360d;
while (lonVal < -360d) lonVal += 360d;
if (lonVal < 0) lonVal = 360d + lonVal;
return lonVal;
}
private double denorm(double lonVal) {
if (lonVal > 180d) lonVal = -360d + lonVal;
return lonVal;
}
private boolean checkBounds(VisibleRegion reg) {
double left = Math.min(
Math.min(norm(reg.farLeft.longitude), norm(reg.nearLeft.longitude)),
Math.min(norm(reg.farRight.longitude), norm(reg.nearRight.longitude)));
double right = Math.max(
Math.max(norm(reg.farLeft.longitude), norm(reg.nearLeft.longitude)),
Math.max(norm(reg.farRight.longitude), norm(reg.nearRight.longitude)));
double top = Math.max(
Math.max(reg.farLeft.latitude, reg.nearLeft.latitude),
Math.max(reg.farRight.latitude, reg.nearRight.latitude));
double bottom = Math.min(
Math.min(reg.farLeft.latitude, reg.nearLeft.latitude),
Math.min(reg.farRight.latitude, reg.nearRight.latitude));
boolean limitBounds = left < MIN_LONGITUDE || right > MAX_LONGITUDE ||
bottom < MIN_LATITUDE || top > MAX_LATITUDE;
return !limitBounds;
}
private void init(Context c) {
try {
MapsInitializer.initialize(c);
} catch (GooglePlayServicesNotAvailableException e) {
e.printStackTrace();
}
mContext = c;
mHandler.post(new Runnable() {
@Override
public void run() {
GoogleMap map = getMap();
if (map != null) {
getMap().getUiSettings().setZoomControlsEnabled(false);
map.getUiSettings().setAllGesturesEnabled(false);
map.moveCamera(CameraUpdateFactory.newLatLngZoom(
new LatLng(DEF_LATITUDE, DEF_LONGITUDE), DEF_ZOOM));
mLastCorrectRegion = map.getProjection().getVisibleRegion();
mGestureDetector = new GestureDetector(mContext, mGestudeListener);
mScaleGestureDetector = new ScaleGestureDetector(mContext, mScaleGestudeListener);
} else mHandler.post(this);
}
});
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
if (mGestureDetector != null) mGestureDetector.onTouchEvent(event);
if (mScaleGestureDetector != null) mScaleGestureDetector.onTouchEvent(event);
return super.onInterceptTouchEvent(event);
}
}
片段,我的XML布局中定义:
Definition within my xml-layout of fragment:
<com.package....RestrictedMapView
android:id="@+id/mapview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
在XML文件中,可以定义自定义缩放/定位按钮和设置单击侦听器手动操控相机(在这种情况下,你必须检查MAX_ZOOM和MIN_ZOOM,并检查当前位置是否在允许范围内)。
In xml file it is possible to define custom zoom/location buttons and set click listeners for manual manipulating camera (in this case you have to check MAX_ZOOM and MIN_ZOOM, and check if the current location is within the allowed bounds).
这篇关于限制滚动和缩放谷歌地图Android的API V2的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!