为地图添加边界以避免在特定区域外滑动

我的应用程序显示地图,我希望用户不能滑过某个地区。 所以我试图添加边界,但它使应用程序崩溃。 这是工作代码:

public class MapViewer extends Activity implements OnInfoWindowClickListener { private LatLng defaultLatLng = new LatLng(42.564241, 12.22759); private GoogleMap map; private int zoomLevel = 5; private Database db = new Database(this); protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.mapviewer); try { map = ((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap(); if (map != null) { map.setMyLocationEnabled(true); map.setMapType(GoogleMap.MAP_TYPE_NORMAL); map.getUiSettings().setRotateGesturesEnabled(false); map.moveCamera(CameraUpdateFactory.newLatLngZoom(defaultLatLng, zoomLevel)); this.addMerchantMarkers(new MarkerOptions()); map.setOnInfoWindowClickListener(this); } } catch (NullPointerException e) { e.printStackTrace(); } } @Override public void onPause() { if (map != null) { map.setMyLocationEnabled(false); map.setTrafficEnabled(false); } super.onPause(); } public void addMerchantMarkers(MarkerOptions mo) { SQLiteDatabase dbRead = db.getReadableDatabase(); String[] columns = {"title", "addr", "lat", "lon"}; Cursor result = dbRead.query("merchants", columns, null, null, null, null, null); while(result.moveToNext()) { String merchant = result.getString(0); String address = result.getString(1); float lat = result.getFloat(2); float lon = result.getFloat(3); LatLng pos = new LatLng(lat, lon); map.addMarker(mo.position(pos) .title(merchant) .snippet(address) .icon(BitmapDescriptorFactory.fromResource(R.drawable.marker_50)));; } } } 

这是我添加onCreate方法导致崩溃的代码:

  LatLngBounds.Builder builder = new LatLngBounds.Builder(); builder.include(new LatLng(47.09194444, 18.52166666)); builder.include(new LatLng(36.448311, 6.62555555)); LatLngBounds bounds = builder.build(); CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, 30); map.animateCamera(cu); 

这里是LogCat:

 08-10 20:59:41.689: E/AndroidRuntime(6304): FATAL EXCEPTION: main 08-10 20:59:41.689: E/AndroidRuntime(6304): Process: com.example.myapp, PID: 6304 08-10 20:59:41.689: E/AndroidRuntime(6304): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.myapp/com.example.myapp.MapViewer}: java.lang.IllegalStateException: Error using newLatLngBounds(LatLngBounds, int): Map size can't be 0. Most likely, layout has not yet occured for the map view. Either wait until layout has occurred or use newLatLngBounds(LatLngBounds, int, int, int) which allows you to specify the map's dimensions. 08-10 20:59:41.689: E/AndroidRuntime(6304): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2215) 08-10 20:59:41.689: E/AndroidRuntime(6304): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2264) 08-10 20:59:41.689: E/AndroidRuntime(6304): at android.app.ActivityThread.access$800(ActivityThread.java:144) 08-10 20:59:41.689: E/AndroidRuntime(6304): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1205) 08-10 20:59:41.689: E/AndroidRuntime(6304): at android.os.Handler.dispatchMessage(Handler.java:102) 08-10 20:59:41.689: E/AndroidRuntime(6304): at android.os.Looper.loop(Looper.java:136) 08-10 20:59:41.689: E/AndroidRuntime(6304): at android.app.ActivityThread.main(ActivityThread.java:5139) 08-10 20:59:41.689: E/AndroidRuntime(6304): at java.lang.reflect.Method.invokeNative(Native Method) 08-10 20:59:41.689: E/AndroidRuntime(6304): at java.lang.reflect.Method.invoke(Method.java:515) 08-10 20:59:41.689: E/AndroidRuntime(6304): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:796) 08-10 20:59:41.689: E/AndroidRuntime(6304): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:612) 08-10 20:59:41.689: E/AndroidRuntime(6304): at dalvik.system.NativeStart.main(Native Method) 08-10 20:59:41.689: E/AndroidRuntime(6304): Caused by: java.lang.IllegalStateException: Error using newLatLngBounds(LatLngBounds, int): Map size can't be 0. Most likely, layout has not yet occured for the map view. Either wait until layout has occurred or use newLatLngBounds(LatLngBounds, int, int, int) which allows you to specify the map's dimensions. 08-10 20:59:41.689: E/AndroidRuntime(6304): at mut.b(Unknown Source) 08-10 20:59:41.689: E/AndroidRuntime(6304): at oxp.a(Unknown Source) 08-10 20:59:41.689: E/AndroidRuntime(6304): at oxi.a(Unknown Source) 08-10 20:59:41.689: E/AndroidRuntime(6304): at oyf.b(Unknown Source) 08-10 20:59:41.689: E/AndroidRuntime(6304): at grl.onTransact(SourceFile:92) 08-10 20:59:41.689: E/AndroidRuntime(6304): at android.os.Binder.transact(Binder.java:361) 08-10 20:59:41.689: E/AndroidRuntime(6304): at com.google.android.gms.maps.internal.IGoogleMapDelegate$a$a.animateCamera(Unknown Source) 08-10 20:59:41.689: E/AndroidRuntime(6304): at com.google.android.gms.maps.GoogleMap.animateCamera(Unknown Source) 08-10 20:59:41.689: E/AndroidRuntime(6304): at com.example.myapp.MapViewer.onCreate(MapViewer.java:59) 08-10 20:59:41.689: E/AndroidRuntime(6304): at android.app.Activity.performCreate(Activity.java:5231) 08-10 20:59:41.689: E/AndroidRuntime(6304): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087) 08-10 20:59:41.689: E/AndroidRuntime(6304): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2169) 08-10 20:59:41.689: E/AndroidRuntime(6304): ... 11 more 

Solutions Collecting From Web of "为地图添加边界以避免在特定区域外滑动"

你可以使用MapLoadedCallBack;

 map.setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() { @Override public void onMapLoaded() { map.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 30)); } }); 

也可以把这个事件发生在prier上面。

  map.setOnCameraChangeListener(new GoogleMap.OnCameraChangeListener() { @Override public void onCameraChange(CameraPosition arg0) { map.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 30)); } }); 

您可以通过遵循日志中的build议来防止发生错误:

“…使用newLatLngBounds(LatLngBounds,int,int,int),它允许你指定地图的尺寸​​。”

额外的参数是屏幕的宽度和高度。 以下是您的更新代码的外观:

 LatLngBounds.Builder builder = new LatLngBounds.Builder(); builder.include(new LatLng(47.09194444, 18.52166666)); builder.include(new LatLng(36.448311, 6.62555555)); LatLngBounds bounds = builder.build(); // begin new code: int width = getResources().getDisplayMetrics().widthPixels; int height = getResources().getDisplayMetrics().heightPixels; int padding = (int) (width * 0.12); // offset from edges of the map 12% of screen CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, width, height, padding); // end of new code map.animateCamera(cu); 

onMapReady()的文档明确指出,您必须等待onMapReadyCallback和ViewTreeObserver.OnGlobalLayoutListener:

请注意,这并不能保证地图已经过布局。 因此,调用callback方法的时间可能还没有确定地图的大小。 如果您需要了解维度或在API中调用需要了解维度的方法,请获取地图的视图并注册一个ViewTreeObserver.OnGlobalLayoutListener。

这是相当不方便的,但一个办法就是使用RxJava。 你可以发出两个观察对象,第一个在onMapReady中,第二个在onGlobalLayout中,然后一起压缩,做你需要做的事情。 这样你可以确定两个callback都被解雇了。

导致:java.lang.IllegalStateException:使用newLatLngBounds(LatLngBounds,int)的错误:地图大小不能为0.最有可能的是,布局还没有发生的地图视图。 要么等到布局发生,要么使用允许指定地图尺寸的newLatLngBounds(LatLngBounds,int,int,int)。

从文档https://developer.android.com/reference/com/google/android/gms/maps/CameraUpdateFactory.html#newLatLngBounds(com.google.android.gms.maps.model.LatLngBounds,int

不要更换摄像头,直到地图经过布局(为了使此方法正确确定合适的边界框和缩放级别,地图必须具有大小)。 否则会抛出IllegalStateExceptionexception。 这是不够的地图是可用的(即getMap()返回一个非空的对象); 包含地图的视图也必须经过布局,以确定其尺寸。 如果您不能确定发生了这种情况,请改为使用newLatLngBounds(LatLngBounds,int,int,int),并手动提供地图的尺寸​​。

注意: getMap()可以返回null。 在初始化GoogleMap对象之前,最好检查Google Play服务的可用性。

 Caused by: java.lang.IllegalStateException: Map size should not be 0. Most likely, layout has not yet occured for the map view. 

这个错误背后的原因是因为地图布局还没有完成,所以你应该在你的调用中实现OnMapReadyCallback,这将确保你的代码只会在你的布局完成后运行,或者实现下面的callback

 map.setOnCameraChangeListener(new GoogleMap.OnCameraChangeListener() { @Override public void onCameraChange(CameraPosition arg0) { map.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 30)); } }); 

重复的链接

用CameraUpdateFactory.newLatLngBounds崩溃moveCamera

IllegalStateException映射大小不应该是0

我不,如果有一种方法来合并这个链接。 我希望我帮助

我已经创build了一种方法,将两个callback函数onMapReady和onGlobalLayout合并成一个单独的observable,只有当两个事件都被触发时才会发射。

https://gist.github.com/abhaysood/e275b3d0937f297980d14b439a8e0d4a

 public final class OnMapAndLayoutReady { private OnMapAndLayoutReady() { } /** * Converts {@link OnMapReadyCallback} to an observable. * Note that this method calls {@link MapView#getMapAsync(OnMapReadyCallback)} so you there is no * need to initialize google map view manually. */ private static Observable<GoogleMap> loadMapObservable(final MapView mapView) { return Observable.create(new Observable.OnSubscribe<GoogleMap>() { @Override public void call(final Subscriber<? super GoogleMap> subscriber) { OnMapReadyCallback mapReadyCallback = new OnMapReadyCallback() { @Override public void onMapReady(GoogleMap googleMap) { subscriber.onNext(googleMap); } }; mapView.getMapAsync(mapReadyCallback); } }); } /** * Converts {@link ViewTreeObserver.OnGlobalLayoutListener} to an observable. * This methods also takes care of removing the global layout listener from the view. */ private static Observable<MapView> globalLayoutObservable(final MapView view) { return Observable.create(new Observable.OnSubscribe<MapView>() { @Override public void call(final Subscriber<? super MapView> subscriber) { final ViewTreeObserver.OnGlobalLayoutListener globalLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { view.getViewTreeObserver().removeOnGlobalLayoutListener(this); subscriber.onNext(view); } }; view.getViewTreeObserver().addOnGlobalLayoutListener(globalLayoutListener); } }); } /** * Takes {@link #globalLayoutObservable(MapView)} and {@link #loadMapObservable(MapView)} and zips their result. * This means that the subscriber will only be notified when both the observables have emitted. */ public static Observable<GoogleMap> onMapAndLayoutReadyObservable(final MapView mapView) { return Observable.zip(globalLayoutObservable(mapView), loadMapObservable(mapView), new Func2<MapView, GoogleMap, GoogleMap>() { @Override public GoogleMap call(MapView mapView, GoogleMap googleMap) { return googleMap; } }); } } 

将调用放入可运行的程序中,并将其发布到视图处理程序,如下所示:

  mapFragment.getView().post(new Runnable() { @Override public void run() { map.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds.build(), CAMERA_PADDING)); } }); 

当视图已经布置好后,runnable将执行并正确定位地图。 ahmadalibalochs回答的问题是,在正确定位自己之前,你会看到全球的闪光。 发布到视图处理程序,解决了这个问题。

这对我工作:

 @Override protected void onCreate(Bundle savedInstanceState) { ... mMapFragment.getMapAsync(this); } @Override public void onMapReady(GoogleMap googleMap) { mMapFragment.getView().getViewTreeObserver().addOnGlobalLayoutListener(this); } @Override public void onGlobalLayout() { mMapFragment.getView().getViewTreeObserver().removeOnGlobalLayoutListener(this); //Only after onMapReady & onGlobalLayout newLatLngBounds will be available initMapPosition(); //newLatLngBounds here }