在较旧的Android版本的图层列表中的矢量Drawable

Sem*_*dog 31 android drawable android-vectordrawable

在较新的Android版本上,以下代码:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
            <shape android:shape="oval">
                <solid android:color="#bdbdbd" />
                <size
                    android:width="60dp"
                    android:height="60dp" />
            </shape>
    </item>
    <item
        android:drawable="@drawable/ic_library_books_black_24dp"
        android:gravity="center"
        android:width="40dp"
        android:height="40dp"
        >
    </item>
</layer-list>
Run Code Online (Sandbox Code Playgroud)

完美地生产:

导航drawable显示在灰色圆背景的白色名单

然而,早期的Android版本(API 16和19,来自我测试过的)根本不喜欢这个,我得到了

E/AndroidRuntime: FATAL EXCEPTION: main
              Process: package.app, PID: 11490
              android.view.InflateException: Binary XML file line #26: Error inflating class ImageView
Run Code Online (Sandbox Code Playgroud)

通货膨胀.我用过app:srcCompat所有的ImageViews,所以没有问题.

标准矢量Drawables也可以正常工作,但放在layer-list它们时会造成混乱.有没有解决方法?

Rap*_*kle 28

仅在API 23(Marshmallow)及更高版本中支持图层列表中可绘制矢量的宽度/高度属性.如果您在Android Studio编辑器中查看可绘制的图层列表,这些属性应该在它们周围有黄色块,同时警告这将在旧设备上无法可靠地运行.

但我认为你可以摆脱警告并实现这样的中心效果:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape android:shape="oval">
            <solid android:color="#bdbdbd" />
            <size
                android:width="60dp"
                android:height="60dp" />
        </shape>
    </item>
    <item
        android:drawable="@drawable/ic_library_books_black_24dp"
        android:top="10dp"
        android:bottom="10dp"
        android:left="10dp"
        android:right="10dp">
    </item>
</layer-list>
Run Code Online (Sandbox Code Playgroud)

我在旧的API 15手机上进行了测试,它运行良好.我希望这也适合你.

更新:

在此答案的先前版本中,我建议不要使用vectorDrawables.useSupportLibrary = true图层列表,因为它会导致崩溃.但是,我最近了解了一个似乎可以修复崩溃的解决方法(同时避免了@android开发人员正确提到的胖的自动生成的png文件).以下是对正常工作需要采取的措施的总结:

一定要在xml中使用srcCompat.

    <android.support.v7.widget.AppCompatImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:srcCompat="@drawable/layer_list_with_svg" />
Run Code Online (Sandbox Code Playgroud)

将'vectorDrawables.useSupportLibrary'添加到app/build.gradle

 android {
   defaultConfig {
     vectorDrawables.useSupportLibrary = true
   }
 }
Run Code Online (Sandbox Code Playgroud)

将'setCompatVectorFromResourcesEnabled(true)'添加到onCreate

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
    setContentView(R.layout.activity_main);
}
Run Code Online (Sandbox Code Playgroud)

为什么所有这一切都是必要的?

正如一位知识渊博的人向我解释的那样,这与Android如何加载compat矢量drawables有关.如果您正在使用,vectorDrawables.useSupportLibrary = true那么图像视图将VectorDrawableCompat在您使用时加载drawable app:srcCompat.当你的图层列表drawable膨胀时,它无法弄清楚如何创建那些引用的矢量drawables.但是如果你打开setCompatVectorFromResourcesEnabled它会尝试将矢量可绘制加载挂钩到比图像视图及其app:srcCompat属性低得多的水平,这样就可以弄清楚如何加载图层列表中引用的矢量drawable.

  • 在API级别19不适用于我 (3认同)
  • 在我添加AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)之前,应用程序崩溃了;在Application onCreate中,而不在Activity中。因为我在主题中使用了图层列表作为初始屏幕。 (2认同)

Lew*_*ary 9

这个答案借鉴了AppCompat - Chris Banes 的载体时代(在支持库中工作).对于这个问题,我们特别关注标题为"魔术"方式的部分.

您遇到的崩溃是因为支持库默认情况下只允许某些方式使用VectorDrawables,而layer-list不是其中之一.

您可以将一个特定的代码块添加到Activity的顶部以启用其他VectorDrawable用途,例如<layer-list>:

static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}
Run Code Online (Sandbox Code Playgroud)

注意:链接的文章在此方法名称中包含一个拼写错误,使用"FromSources",它应该是"FromResources",如上所示.

您需要将此添加到要使用此类drawable的每个Activity,或者可能将其包含在您的其他Activities扩展的BaseActivity类中.

根据文章,这应该意味着以下将现在工作:

DrawableContainers,它引用其他只包含矢量资源的drawables资源.

... StateListDrawable ... InsetDrawable,LayerDrawable,LevelListDrawable和RotateDrawable.

应该注意的是,这个方法用"可能"这个词很重要,这可能有用,默认情况下它没有启用,所以要注意并检查它是否真的适合你!

现在这个问题实际上是另一个方面,其他用户Selim AjimiRapunzel Van Winkle在他们的答案中解决了这个问题.<layer-list>有API的之间的一些不同的行为,特别是widthheight你的属性<item>只有在API 23+支撑.这不是导致崩溃的原因,也不会导致您的应用程序崩溃,但这意味着一旦您的映像在早期API中运行,您的映像就不会像预期的那样.

Rapunzel Van Winkle的建议确实似乎是在API中正确定位drawable的好方法(在API 16和24上测试):

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape android:shape="oval">
            <solid android:color="#bdbdbd" />
            <size
                android:width="60dp"
                android:height="60dp" />
        </shape>
    </item>
    <item
        android:drawable="@drawable/ic_library_books_black_24dp"
        android:top="10dp"
        android:bottom="10dp"
        android:left="10dp"
        android:right="10dp"
        >
    </item>
</layer-list>
Run Code Online (Sandbox Code Playgroud)

  • 请注意,由于AppCompat中的错误,直接在`item`元素上设置重力属性会使绘图对象至少在Pre-lollipop API上得到拉伸。在解决该问题之前,您将不得不使用png /位图并在位图元素上设置重力(如果需要设置重力)。 (2认同)

Sel*_*imi 1

<?xml version="1.0" encoding="utf-8"?>
<layer-list
    xmlns:android="http://schemas.android.com/apk/res/android" >
    <item
        android:drawable="@[package:]drawable/drawable_resource"
        android:id="@[+][package:]id/resource_name"
        android:top="dimension"
        android:right="dimension"
        android:bottom="dimension"
        android:left="dimension" />
</layer-list>
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,这里 没有宽度/高度属性......

您可以将位图附加到项目我认为这是最好的解决方案