IllegalStateException:填充后视图尺寸太小

IllegalStateException: View size is too small after padding

我正在开发一个 android 应用程序。在此应用程序中,我在片段中显示了一个 MapView。如果我的设备旋转并且我尝试使用以下方法之一移动相机:

mapa.animateCamera(cameraUpdate);

mapa.moveCamera(cameraUpdate);

然后我的应用程序崩溃并显示以下错误:

java.lang.IllegalStateException: View size is too small after padding
 at com.google.a.a.ab.b(Unknown Source)
 at com.google.maps.api.android.lib6.gmm6.c.a.a(Unknown Source)
 at com.google.maps.api.android.lib6.gmm6.c.a.a(Unknown Source)
 at com.google.maps.api.android.lib6.d.dw.a(Unknown Source)
 at com.google.maps.api.android.lib6.gmm6.c.a.a(Unknown Source)
 at com.google.maps.api.android.lib6.d.et.a(Unknown Source)
 at com.google.android.gms.maps.internal.j.onTransact(SourceFile:83)
 at android.os.Binder.transact(Binder.java:380)
 at com.google.android.gms.maps.internal.IGoogleMapDelegate$zza$zza.moveCamera(Unknown Source)
 at com.google.android.gms.maps.GoogleMap.moveCamera(Unknown Source)
 at com.accionplus.dbdplus.utils.MapUtils.centrarCamara(MapUtils.java:88)
 at com.accionplus.dbdplus.utils.MapUtils.centrarCamara(MapUtils.java:52)
 at com.accionplus.dbdplus.controladores.pdv.RutaProgramadaFragment.onMyLocationButtonClick(RutaProgramadaFragment.java:274)
 at com.google.android.gms.maps.GoogleMap.onMyLocationButtonClick(Unknown Source)
 at com.google.android.gms.maps.internal.zzo$zza.onTransact(Unknown Source)
 at android.os.Binder.transact(Binder.java:380)
 at com.google.android.gms.maps.internal.be.a(SourceFile:81)
 at com.google.maps.api.android.lib6.d.ak.onClick(Unknown Source)
 at android.view.View.performClick(View.java:5156)
 at android.view.View$PerformClick.run(View.java:20755)
 at android.os.Handler.handleCallback(Handler.java:739)
 at android.os.Handler.dispatchMessage(Handler.java:95)
 at android.os.Looper.loop(Looper.java:145)
 at android.app.ActivityThread.main(ActivityThread.java:5832)
 at java.lang.reflect.Method.invoke(Native Method)
 at java.lang.reflect.Method.invoke(Method.java:372)
 at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1399)
 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194)

我已经 google 完成了,但没有成功。我刚刚发现这是 google 的一个已报告问题,但我不知道 "solve" 这个问题是否有任何解决方法。谁能帮帮我?

编辑:我正在添加更多代码

<RelativeLayout 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"
                tools:context="com.accionplus.dbdplus.controladores.pdv.RutaProgramadaActivity">

    <LinearLayout
        android:id="@+id/card_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#15000000"
        android:orientation="vertical"/>

    <LinearLayout
        android:id="@+id/filtro_ll"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/card_container"
        android:layout_margin="10dp"
        android:gravity="left|top"
        android:orientation="horizontal"
        android:weightSum="1">

        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="0.7"
            android:gravity="left|top"
            android:orientation="vertical">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:gravity="left"
                android:orientation="horizontal"
                android:weightSum="1">

                <ImageButton
                    android:id="@+id/seleccionar_fecha_btn"
                    android:layout_width="wrap_content"
                    android:layout_height="35dp"
                    android:background="@drawable/button"
                    android:src="@drawable/ic_date"
                    android:text="@string/buscar"
                    android:textColor="@color/color_text_primary"/>

                <TextView
                    android:id="@+id/fecha_consulta_tv"
                    android:layout_width="match_parent"
                    android:layout_height="35dp"
                    android:layout_alignParentTop="true"
                    android:layout_marginLeft="5dp"
                    android:background="@drawable/rectangle"
                    android:gravity="center"/>
            </LinearLayout>

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="10dp"
                android:background="@drawable/rectangle">

                <Spinner
                    android:id="@+id/tipo_ruta_sp"
                    android:layout_width="fill_parent"
                    android:layout_height="35dp"
                    android:layout_gravity="center"
                    />
            </LinearLayout>

        </LinearLayout>
    </LinearLayout>

    <com.google.android.gms.maps.MapView
        android:id="@+id/map"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@+id/filtro_ll"/>

    <ProgressBar
        android:id="@+id/progress_bar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:foregroundGravity="center|top"
        android:visibility="gone"/>

</RelativeLayout>

这是点击 MyLocationButton 的时间:

mMap.setOnMyLocationButtonClickListener(new GoogleMap.OnMyLocationButtonClickListener() {
            @Override
            public boolean onMyLocationButtonClick() {
                MapUtils.centrarCamara(getActivity(), mMap, mPuntosFinales);
                return true;
            }
        });

这是MapUtils.centrarCamara()方法:

public static void centrarCamara(Context contexto, GoogleMap mapa, LatLng... posiciones) {
        centrarCamara(contexto, mapa, Boolean.TRUE, posiciones);
    }

    public static void centrarCamara(Context contexto, GoogleMap mapa, boolean animado,
                                     LatLng... posiciones) {
        if (mapa == null) {
            return;
        }

        LatLngBounds.Builder builder = new LatLngBounds.Builder();
        for (LatLng posicion : posiciones) {
            builder.include(posicion);
        }

        LatLngBounds bounds = builder.build();

        CameraUpdate cu = CameraUpdateFactory
                .newLatLngBounds(bounds, ViewUtils.dpAPixeles(MARKERS_DP_OFFSET, contexto));

        if (animado) {
            mapa.animateCamera(cu);
        } else {
            mapa.moveCamera(cu);
        }
    }

ViewUtils.dpAPixeles:

public static int dpAPixeles(int dp, Context contexto) {
    Resources r = contexto.getResources();
    int px = (int) TypedValue
            .applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, r.getDisplayMetrics());

    return px;
}

调用mapa.moveCamera()mapa.animateCamera()时出现异常;

来自the documentation

Do not change the camera with this camera update until the map has undergone layout (in order for this method to correctly determine the appropriate bounding box and zoom level, the map must have a size). Otherwise an IllegalStateException will be thrown. It is NOT sufficient for the map to be available (i.e. getMap() returns a non-null object); the view containing the map must have also undergone layout such that its dimensions have been determined. If you cannot be sure that this has occured, use newLatLngBounds(LatLngBounds, int, int, int) instead and provide the dimensions of the map manually.

因此,您的问题可能是当您调用 mapa.animateCamera(cameraUpdate)mapa.moveCamera(cameraUpdate).

时地图没有尺寸

无论如何,正如您所说,当您旋转设备时会抛出异常,我会说真正的问题是您在调用 newLatLngBounds 时使用的填充(ViewUtils.dpAPixeles(MARKERS_DP_OFFSET, contexto) ) 导致问题(也许填充大于视图的高度/2?)。有一个与 Google 地图相关的已注册问题 (4773) 可以帮助您解决问题。如那里所述,一种可能的解决方法是根据方向设置 cameraUpdate:

if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
    cu = CameraUpdateFactory.newLatLngBounds(bounds, ViewUtils.dpAPixeles(MARKERS_DP_OFFSET, contexto));
} else {
    // Use another method to get your camera update, for example CameraUpdateFactory.newLatLng(latLng);
}

将填充 300 设置为 150。它对我有用。

  map.animateCamera(
                CameraUpdateFactory.newLatLngBounds(boundsLatLongs, 150),
                1000, null);

我已经尝试了很多解决方案,但其中 none 确实解决了我的问题,即填充超出了地图的实际大小。

我的解决方案是只填充一个小的填充,然后缩小以提供相同的结果。

此代码来自我的应用程序,对我来说效果很好。

    public static void fitThePoints(GoogleMap map, ArrayList<LatLng> points) {
    //Calculate the markers to get their position
    LatLngBounds.Builder b = new LatLngBounds.Builder();
    for (LatLng point : points) b.include(point);

    //Change the padding as per needed
    map.moveCamera(CameraUpdateFactory.newLatLngBounds(b.build(), ConvertUtils.dp2px(30)));
    map.moveCamera(CameraUpdateFactory.zoomTo(map.getCameraPosition().zoom - 0.5f));
}

错误 react-native-maps

解决方案是为地图视图组件提供最小宽度和高度,因为它在其父视图之前被布局。

对于Android,我也尝试了各种解决方案,终于找到了崩溃的主要原因。

崩溃背后的主要原因是分屏 Support/Multi-Window 在 Android 7 - 7.1.2 中的支持(API:24 – 25)。

LatLngBounds 根据设备宽度的百分比设置填充,以便它适用于小型设备。 这甚至适用于具有 4 英寸显示屏的小型设备,但是,它在 Android 7.0 中的 multi-window 模式和之前支持 multi-window 模式的设备上失败,例如。盖乐世 S7.

解决方案是选择宽度和高度之间的最小度量,因为在 Multi-window 模式下,高度可以小于宽度:

final int width = getResources().getDisplayMetrics().widthPixels;
final int height = getResources().getDisplayMetrics().heightPixels;
final int minMetric = Math.min(width, height);
final int padding = (int) (minMetric * paddingPercentage);

您可以根据需要选择填充百分比。

对于移动相机,

googleMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds.build(), width, height, padding));

对于动画相机,

googleMap.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds.build(), width, height, padding));

我下面的解决方案适用于地图,该地图大约占屏幕的 60%,分辨率较小 (1280x720)(代码为 Kotlin)

 val builder = LatLngBounds.Builder()
            //storing the MarkerOptions in a hashmap
            builder.include(markers[MarkerType.START]?.position)
            builder.include(markers[MarkerType.END]?.position)
            val bounds = builder.build()
            val width = resources.displayMetrics.widthPixels
            val  height = resources.displayMetrics.heightPixels
            val  minMetric = min(width, height)
            //divide the smallest screen value by 10 , to get a value around 100
            val  padding = minMetric.div(10) 
            val cu = CameraUpdateFactory.newLatLngBounds(bounds, padding)
            googleMap?.animateCamera(cu)