【问题标题】:Vector Drawable in Layer List on Older Android Versions在旧 Android 版本的图层列表中可绘制矢量
【发布时间】:2017-08-10 15:46:39
【问题描述】:

在较新的 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>

完美地产生了这个:

但是,早期的 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

通货膨胀。我所有的 ImageView 都使用了app:srcCompat,所以那里没有问题。

标准矢量可绘制对象也可以正常工作,但是当放置在 layer-list 中时,它们会造成混乱。有什么解决方法吗?

【问题讨论】:

  • 这个运气好吗?

标签: android drawable android-vectordrawable


【解决方案1】:

图层列表中可绘制矢量的宽度/高度属性仅在 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>

我在旧的 API 15 手机上对此进行了测试,它运行良好。我希望这对你也有用。

更新:

在此答案的先前版本中,我建议不要将 vectorDrawables.useSupportLibrary = true 与层列表一起使用,因为它会导致崩溃。但是,我最近了解到一种似乎可以修复崩溃的解决方法(同时避免 @android developer 正确提到的胖自动生成的 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 加载兼容矢量可绘制对象的方式有关。如果您使用vectorDrawables.useSupportLibrary = true,那么当您使用app:srcCompat 时,图像视图将加载VectorDrawableCompat drawables。当您的图层列表可绘制对象被夸大时,它无法弄清楚如何创建那些引用的矢量可绘制对象。但是,如果你打开setCompatVectorFromResourcesEnabled,它会尝试在比图像视图及其app:srcCompat 属性低得多的级别挂钩矢量可绘制对象加载,因此它能够弄清楚如何加载层中引用的矢量可绘制对象列表。

【讨论】:

  • 我不认为您的项目仅使用 VectorDrawable 本身。我认为它使用 API 15 的自动生成文件。
  • 它确实适用于 API 级别 19。但请参阅更新的答案以获取更多信息。
  • 应用程序崩溃,直到我添加 AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);在应用程序 onCreate 中,而不是在 Activity 中。因为我在主题中使用图层列表作为启动画面。
【解决方案2】:

此答案来自 Chris Banes(在支持库工作)的文章 AppCompat - Age of the Vectors。对于这个问题,我们正在专门研究标题为“神奇”方式的部分。

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

您可以将特定代码块添加到 Activity 的顶部,以启用其他 VectorDrawable 使用,例如 &lt;layer-list&gt;

static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

注意:链接的文章中这个方法名有错别字,使用“FromSources”,如上图应该是“FromResources”。

您需要将此添加到每个要使用此类可绘制对象的 Activity,或者可能将其包含在您的其他 Activity 扩展的 BaseActivity 类中。

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

引用其他仅包含矢量资源的可绘制资源的DrawableContainers。

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

但应该注意,此方法大量使用“可能”一词,这可能有效,并且默认情况下未启用,因此请注意并检查它是否真的适合您!

现在这个问题实际上还有另一个维度,感谢其他用户 Selim AjimiRapunzel Van Winkle 在他们的回答中解决了这个问题。 &lt;layer-list&gt; 在 API 之间有一些不同的行为,特别是您的 &lt;item&gt;widthheight 属性仅在 API 23+ 中受支持。这不是导致您崩溃的原因,也不会导致您的应用崩溃,但意味着您的图像在早期 API 中运行后将不会看起来像预期的那样。

Rapunzel Van Winkle 的建议似乎确实是跨 API 正确定位可绘制对象的好方法(在 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>

【讨论】:

  • 非常感谢!它适用于层列表中的 KitKat。
  • 请注意,由于 AppCompat 中的一个错误,直接在 item 元素上设置重力属性会使可绘制对象至少在 Pre-lollipop API 上被拉伸。在解决该问题之前,您只能使用 png/位图并在位图元素上设置重力(如果您需要设置重力)。
  • 根据文档,不建议使用 setCompatVectorFromResourcesEnabled:“此功能默认为禁用,因为启用它可能会导致内存使用问题以及更新配置实例的问题。如果您手动更新配置,那么您可能不想启用此功能。您已被警告。 .链接:developer.android.com/reference/android/support/v7/app/…。我在回答中提供了替代方案。
【解决方案3】:
<?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 没有宽度/高度属性...

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

【讨论】:

    【解决方案4】:

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

    您可以使用 VectorDrawableCompat 回到 API 级别 7 和 AnimatedVectorDrawableCompat 在所有运行 Android 5.0 的设备上(API 11 级)及更高级别。 Android加载drawables的方式,不是每个地方 接受可绘制 ID(例如在 XML 文件中)支持加载 矢量绘图。 android.support.v7.appcompat 包增加了一个 使矢量绘图易于使用的功能数量。第一, 当您将 android.support.v7.appcompat 包与 ImageView 或 使用 ImageButton 和 FloatingActionButton 等子类,您可以 使用新的 app:srcCompat 属性来引用矢量可绘制对象 以及 android:src 可用的任何其他可绘制对象

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

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

    你能做什么?

    几个可能的解决方案:

    1. 为您在 LayerDrawable 中使用的 VectorDrawable 提供替代可绘制对象。比如放到 res/drawable-xxhdpi 里,把 VectorDrawable 放到 res/drawable-anydpi 里。

    2. 在您的应用程序具有能够使用 VectorDrawable 的 minSdk 之前,请勿使用 vectorDrawables.useSupportLibrary = true。这将起作用,因为 IDE 将为您生成 PNG 文件。

    3. 以编程方式创建 layerList(例如 here),为了放置 VectorDrawable,请使用 AppCompatResources.getDrawable。除了放置 VectorDrawable 的部分之外,您还可以使用 XML 来完成。

    顺便说一句,它受到限制的原因是谷歌未能使其高效且没有问题。您可以通过使用 AppCompatDelegate.setCompatVectorFromResourcesEnabled(true) 获得他们最初的完全支持尝试,但正如文档所说,您正在接受risk here

    此功能默认为禁用,因为启用它可能会导致问题 内存使用情况,以及更新配置实例的问题。如果 您手动更新配置,那么您可能不希望 启用此功能。 您已收到警告

    【讨论】:

    • 嘿!您提到的是在运行时更改可绘制对象!对于 API >= 16 如何做到这一点,我拥有相同的 XML 文件效果很好,但我无法在运行时更改可绘制图层!
    • 可以参考this
    • @VasilVasilev 您只需要通过以下方式使用 VectorDrawable:AppCompatResources.getDrawable(...)。另外,请确保您的 VectorDrawable 文件位于 res/drawable-nodpi 中,而不是其他任何地方(与向导所做的相反)。不要忘记启用vectorDrawables.useSupportLibrary=true的标志
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多