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

时间:2017-03-19 10:18:21

标签: 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>

完美地产生了这个:

Vector drawable showing white lists on grey circular background

然而,早期的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
通货膨胀后。我已将app:srcCompat用于我的所有ImageView,因此没有任何问题。

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

4 个答案:

答案 0 :(得分:21)

图层列表中矢量绘图的宽度/高度属性仅在API 23(Marshmallow)及更高版本中受支持。如果你在Android Studio编辑器中查看你的图层列表drawable,这些属性应该在它们周围有黄色块,并警告说这在旧设备上不能可靠地工作。

但我认为你可以摆脱警告并达到同样的中心效果:

<?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>

我在一台旧的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" />

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

 android {
   defaultConfig {
     vectorDrawables.useSupportLibrary = true
   }
 }

将'setCompatVectorFromResourcesEnabled(true)'添加到onCreate

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
    setContentView(R.layout.activity_main);
}

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

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

答案 1 :(得分:8)

这个答案借鉴了Chris Banes撰写的文章AppCompat - Age of the Vectors(他在支持库中工作)。对于这个问题,我们特别关注标题为 The magic&#39; magic&#39;方式

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

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

static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

注意:链接的文章在此方法名称中包含拼写错误,使用&#34; FromSources&#34;,它应该是&#34; FromResources&#34;如上所示。

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

根据这篇文章,这应该意味着现在可以使用以下内容:

  

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

     

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

应该注意的是,这个方法非常适用于“可能”这个词,这个可能正常工作,并且默认情况下没有启用,所以要注意并检查它真的为你工作!

现在,这个问题实际上是另一个方面,其他用户 Selim Ajimi Rapunzel Van Winkle 可以在答案中解决这个问题。 <layer-list>在API之间有一些不同的行为,特别是{23}中仅支持width的{​​{1}}和height属性。这不是导致崩溃的原因,也不会导致您的应用程序崩溃,但这意味着一旦您的映像在早期的API中运行,您的映像就不会像预期的那样。

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

<item>

答案 2 :(得分: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>

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

您可以将Bitmap追加到项目我认为这是最佳解决方案

答案 3 :(得分:1)

对于旧Android版本,对VectorDrawble的支持为quite limited,假设您使用vectorDrawables.useSupportLibrary = true

  

您可以将VectorDrawableCompat用于API级别7和   运行Android 5.0的所有设备上的AnimatedVectorDrawableCompat(API   等级11)及更高。 Android加载drawables的方式,而不是每个地方   接受可绘制ID,例如在XML文件中,支持加载   矢量drawables。 android.support.v7.appcompat包中添加了一个   一些功能,使其易于使用矢量drawables。首先,   当您使用带有ImageView或的android.support.v7.appcompat包时   使用像ImageButton和FloatingActionButton这样的子类,你可以   使用新的app:srcCompat属性来引用矢量drawables as   以及android:src

可用的任何其他drawable

即使在代码中,您也是有限的:

  

要在运行时更改drawable,可以使用setImageResource()   方法和以前一样。使用AppCompat和app:srcCompat是最多的   将矢量绘图集成到您的应用程序中的万无一失的方法。

你能做什么?

几种可能的解决方案:

  1. 具有您在LayerDrawable中使用的VectorDrawable的替代drawable。例如,将它放在res / drawable-xxhdpi中,将VectorDrawable放入res / drawable-anydpi。

  2. 不要使用vectorDrawables.useSupportLibrary = true,直到您的应用程序具有能够使用VectorDrawable的minSdk。这将起作用,因为IDE将为您生成PNG文件。

  3. 以编程方式创建layerList(示例here),并且为了放置VectorDrawable,请使用AppCompatResources.getDrawable。除了放置VectorDrawable之外,您也可以使用XML。

  4. 顺便说一下,它之所以有限,是因为谷歌未能提高效率而且没有问题。您可以通过使用AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)来获得完全支持的原始尝试,但正如文档所说,您正在使用risk here

      

    此功能默认为禁用,因为启用它可能会导致问题   内存使用情况以及更新配置实例时出现问题。如果   您手动更新配置,然后您可能不想要   启用此功能。 您已收到警告