在棒棒糖崩溃前使用android矢量Drawables


91

我在Lollipop之前在Android中使用矢量可绘制对象,这些是我的某些库和工具版本:

  • Android Studio:2.0
  • Android Gradle插件:2.0.0
  • 编译工具:23.0.2
  • Android支持库:23.3.0

我在应用程序级别添加了此属性 Build.Gradle

android {  
  defaultConfig {  
    vectorDrawables.useSupportLibrary = true  
   }  
}

还值得一提的是,我使用了一个额外的可绘制对象,例如Android官方博客(此处的链接)中所述的LayerDrawable(layer_list),用于为外部的矢量可绘制对象设置可绘制对象app:srcCompat

<level-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/search"/>
</level-list>

您会发现直接引用app:srcCompat之外的矢量可绘制对象将在Lollipop之前失败。但是,当在另一个可绘制容器(例如StateListDrawable,InsetDrawable,LayerDrawable,LevelListDrawable和RotateDrawable)中引用矢量可绘制对象时,AppCompat确实支持加载矢量可绘制对象。通过使用这种 间接方式,您可以在诸如TextView的android:drawableLeft属性之类的情况下使用矢量可绘制对象,该属性通常无法支持矢量可绘制对象。

当我使用时,app:srcCompat一切正常,但是当我使用时:

android:background
android:drawableLeft
android:drawableRight
android:drawableTop
android:drawableBottom

ImageViewImageButtonTextViewEditText之前棒棒糖,它引发厚望:

Caused by: android.content.res.Resources$NotFoundException: File res/drawable/search_toggle.xml from drawable resource ID #0x7f0200a9


要了解如何与drawableLeft,drawableRight,drawableTop,drawableBottom检查出使用VectorDrawable 这个答案
Behzad Bahmanyar

你可以在这里查看我的答案吗?stackoverflow.com/a/40523623/2557258
Yazon2006年

Answers:


102

最新更新-2019年6月

自原始答案以来,支持库已有所更改。现在,即使是Gradle的Android插件也能够在构建时自动生成PNG。因此,下面是目前应该使用的两种新方法。您可以在此处找到更多信息

PNG生成

Gradle可以在构建时根据您的资产自动创建PNG图像。但是,在这种方法中,并非所有xml元素都受支持。此解决方案很方便,因为您无需更改代码或build.gradle中的任何内容。只要确保您使用的是Android Plugin 1.5.0或更高版本以及Android Studio 2.2或更高版本

我在我的应用程序中使用了此解决方案,并且工作正常。无需其他build.gradle标志。无需黑客。如果转到/ build / generated / res / pngs / ...,则可以看到所有生成的PNG。

因此,如果您有一些简单的图标(因为并非所有xml元素都受支持),则此解决方案可能适用。只需更新您的Android Studio和适用于Gradle的Android插件即可。

支持库

也许这是将为您服务的解决方案。如果您来到这里,则意味着您的Android Studio不会自动生成PNG。因此,您的应用程序崩溃了。

或者,也许您根本不希望Android Studio生成任何PNG。

与支持XML元素子集的“自动PNG生成”不同,此解决方案支持所有xml标签。因此,您对矢量可绘制对象具有完全的支持。

您必须首先更新build.gradle以支持它:

android {
  defaultConfig {
    // This flag will also prevents Android Studio from generating PNGs automatically
    vectorDrawables.useSupportLibrary = true
  }
}

dependencies {
  // Use this for Support Library
  implementation 'com.android.support:appcompat-v7:23.2.0' // OR HIGHER

  // Use this for AndroidX
  implementation 'androidx.appcompat:appcompat:1.1.0' // OR HIGHER
}

然后,使用app:srcCompat而不是android:src在加载时VectorDrawables。不要忘记这一点。

对于TextView,如果您使用的androidx是支持库版本,则可以使用app:drawableLeftCompat(或右,上,下)代替app:drawableLeft

如果是CheckBox/ RadioButton,请使用app:buttonCompat代替android:button

如果你不使用androidx的支持库和你的版本minSdkVersion就是17以上或使用按钮,您可以尝试通过设置编程

Drawable icon = AppCompatResources.getDrawable(context, <drawable_id>);
textView.setCompoundDrawablesWithIntrinsicBounds(<leftIcon>,<topIcon>,<rightIcon>,<bottomIcon>);

更新-2016年7月

他们在Android支持库23.4.0中重新启用了
VectorDrawable

对于AppCompat用户,我们添加了一个选择加入 API,以通过AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)从资源重新启用对Vector Drawables的支持(行为在23.2中找到)-请记住,这仍然可能导致内存使用和更新配置实例时出现问题,因此默认情况下为何禁用它。

也许build.gradle设置已过时,您只需要在适当的活动中启用它即可(但是,需要测试)。

现在,要启用它,您必须执行以下操作:

public class MainActivity extends AppCompatActivity {
    static {
        AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
    }

    ...
}

原始答案-2016年4月

我认为这是因为在最新的库版本23.3.0中禁用了Support Vector

根据这一POST

对于AppCompat用户,由于在版本23.2.0 / 23.2.1 (ISSUE 205236)中的实现中发现的问题,我们决定删除允许您在棒棒糖设备上的资源中使用矢量绘制工具的功能。使用app:srcCompat和setImageResource()继续工作。

如果您访问问题ISSUE 205236,它们似乎将来会启用,但是内存问题不会很快得到解决:

在下一个版本中,我添加了一个可选API,您可以在其中重新启用已删除的VectorDrawable支持。它具有与以前相同的警告(内存使用情况和配置更新问题)。

我有一个类似的问题。因此,在我的情况下,我将所有使用vector drawable的图标从资源重新还原为PNG图像(因为即使提供了重新启用选项后,内存问题仍然会发生)。

我不确定这是否是最佳选择,但我认为它可以解决所有崩溃问题。


1
感谢@Guilherme P.但是为什么不删除vectorDrawables.useSupportLibrary = true性能,以重新启用在构建时生成png的功能
Behzad Bahmanyar,2016年

1
由于内存问题,在最新版本v23.3.0中已禁用该功能。这样,他们就无法在运行时生成png ...这就是为什么他们在logcat错误中打印:未知标记向量(或类似的东西)。
W0rmH0le 2016年

4
这是选择加入的说明plus.google.com/+AndroidDevelopers/posts/B7QhFkWZ6YX。不幸的是,VectorDrawables仍无法在Pre-Lollipop设备上运行。我在Support Library 23.4.0上,在defaultConfig {}中调用了“ generatedDensities = []”和“ vectorDrawables.useSupportLibrary = true”。
亚当·赫维兹

1
@AdamHurwitz我更新了答案。似乎重新启用了。但是,您现在必须以其他方式启用它。
W0rmH0le '16

1
@juztcode你是对的。您应该使用“ androidx.appcompat:appcompat:1.1.0”
W0rmH0le

63

我有同样的问题。但是经过大量的研发,我得到了答案。

对于Imageview和ImageButton的使用,app:srcCompat="@drawable/...." 以及Button,Textview等其他视图,而不是"drawableLeft/right..."在XML 中使用,可以通过编程方式将drawables指定为:

button.setCompoundDrawablesWithIntrinsicBounds(AppCompatResources.getDrawable(mContext,R.drawable.ic_share_brown_18dp), null, null, null);

并使用“ AppCompatResources”获取可绘制对象。



39

Guillherme P的回答非常棒。只是做了一点改进,您不需要在每个活动中都添加该行,如果您在Application类中添加了它一次也可以使用。

public class App extends Application {

static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

记住:您仍然需要在gradle中启用支持库的使用:

android {
  defaultConfig {
    vectorDrawables.useSupportLibrary = true
  }
}

另外,当Google重新添加对VectorDrawables的Drawable Containers的支持时,请确保您使用的支持库版本高于v23.4(发行说明

更新资料

对于代码更改:

  1. 确保更新到app:srcCompat接受该android:src属性的每个位置(如果该属性无效(如<bitmap>标记),IDE会警告您)。
  2. 对于drawableLeftdrawableStartdrawableRightdrawableEnd属性中使用TextView或相似的看法,你将不得不以编程方式设置他们现在。设置示例drawableStart

    Drawable drawable = AppCompatResources.getDrawable(
            getContext(),
            R.drawable.your_vector_drawable);
    
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
        textView.setCompoundDrawablesRelativeWithIntrinsicBounds(drawable, null, null, null);
    }

请记住,您需要启用对gradle中的矢量可绘制对象的支持库:vectorDrawables.useSupportLibrary = true
Benny

2
是的 我知道。但是有必要使用包装器使矢量可绘制对象用作TexViews的可绘制对象,因此此答案是不完整的。
cesards '16

1
好答案。对于所有活动都来自自定义基本活动的应用程序来说,它特别有用。

14

我有同样的问题。并通过删除进行修复

vectorDrawables.useSupportLibrary = true

我的目标版本是25,支持库是

 compile 'com.android.support:appcompat-v7:25.3.1'

1
这对我有用。谢谢。我刚刚删除了它vectorDrawables.useSupportLibrary = true
Android Mediocre

我认为这不是执行此操作的正确方法,无论哪种方式,我都同意您的回答!!
哈里斯·雷迪

谢谢。t适用于我的应用。如果将其移除,所有矢量可绘制对象仍然可以使用。该应用使用com.android.support:appcompat-v7:28.0.0

10

棒棒糖上的VectorDrawables应该可以正常使用而无需使用

AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);

如果要在ImageViews中使用VectorDrawables,则可以使用该属性,srcCompat并且该属性将起作用,但在Buttons或TextViews中则不起作用,因此需要将Drawable包装到InsetDrawable或LayerDrawable中。我发现了另一个技巧,如果您使用数据绑定,则可以这样做:

android:drawableLeft="@{@drawable/vector_ic_access_time_24px}"
android:drawableStart="@{@drawable/vector_ic_access_time_24px}"

这将神奇地起作用,我还没有调查幕后发生的事情,但是我想TextView正在使用AppCompatResources或类似方法中的getDrawable方法。


如何在选择器中设置矢量图像?
Tushar Gogna's

在gradle默认中设置vectorDrawables.useSupportLibrary = trueAppCompatDelegate.setCompatVectorFromResourcesEnabled(true)之后 为了避免在Textview中android:drawableleft发生崩溃,请在程序中将左侧的drawble编程设置为textview的示例:textview.setCompoundDrawablesWithIntrinsicBounds(R.drawable.movi​​e,0,0,0);
Afjalur Ra​​hman Rana

7

经过大量的研发,最终获得了针对棒棒糖前置设备崩溃的解决方案。

对于Imageview

  • 使用app:srcCompat而不是android:src

对于TextView / EditText

  • 删除drawableleftdrawableright ....并从drawable java代码中进行设置。

txtview.setCompoundDrawablesWithIntrinsicBounds(AppCompatResources.getDrawable(EventDetailSinglePage.this,R.drawable.ic_done_black_24_n),null,null,null);

对于Build.gradle

vectorDrawables.useSupportLibrary = true


1
这是适用于TextInputEditText的独特解决方案。
heronsanches

1
太好了,这解决了我的问题。这是可以接受的答案。
DJtiwari

6

最简单的使用方式:

app:drawableRightCompat ="@drawable/ic_mobilelogin"
app:drawableEndCompat="@drawable/ic_mobilelogin"
app:srcCompat="@drawable/ic_mobile"

和...仅 app:**Compat用于兼容性。同时添加对build.gradle(模块)的支持

android {
   defaultConfig {
       vectorDrawables.useSupportLibrary = true
   }
}

app:drawableEndCompat和app:drawableRightCompat如果是英语,则几乎是同一件事
Hossam Hassan

5

对于升级到android gradle 3.0及更高版本的任何人,都无需使用AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)或进行设置vectorDrawables.useSupportLibrary = true(添加此操作会导致问题)和use app:srcCompat,它就可以正常工作。

请花两天时间来解决这个问题,并且在Google文档中没有找到任何相关文档...


有趣的是,我正在使用gradle 3.3.0,并且此解决方案有效。但是,Android Studio仍然告诉我启用set vectorDrawables.useSupportLibrary = true。
masterwok

2

我在棒棒糖播放器的设备上使用VectorDrawables,这就是我的方法:-

第1步: 将其放入您的应用级界面。

android {
  defaultConfig {
    vectorDrawables.useSupportLibrary = true
  }
}

第2步:

将其放在Application类中,不要忘记在清单文件中注册Application类。

public class App extends Application {
    static {
        AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
    }
}

第三步:

使用以下方法获取VectorDrawables:

imageView.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.my_vector_drawable));

2

使用下面的代码后。

android {
  defaultConfig {
  vectorDrawables.useSupportLibrary = true  
                }
        }




public class App extends Application {
static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}}

仍然存在以下属性的矢量图像问题

DrawableEnd,DrawableStart,DrawableTop,DrawableBottom,背景

在这种情况下,请按照以下说明进行操作,而不是直接引用矢量图像,而是将选择器标记用作中间可绘制文件。

例:

ic_warranty_icon.xml

<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="17dp"
android:height="24dp"
android:autoMirrored="true"
android:viewportWidth="17"
android:viewportHeight="24">

<path
    android:fillColor="#fff"
    android:pathData="M10.927,15.589l-1.549,0.355a7.47,7.47 0,0 1,-0.878 0.056c-4.136,0 -7.5,-3.364 -7.5,-7.5s3.364,-7.5 7.5,-7.5 7.5,3.364 7.5,7.5c0,3.286 -2.126,6.078 -5.073,7.089zM8.5,2a6.508,6.508 0,0 0,-6.5 6.5c0,3.583 2.917,6.5 6.5,6.5s6.5,-2.917 6.5,-6.5 -2.917,-6.5 -6.5,-6.5z" />

safe_ic_warranty_icon.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/ic_warranty_icon"  />
</selector>

您的TextView /布局。

<TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:drawableStart="@drawable/ic_warranty_icon"
       />


<LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/ic_warranty_icon"
       />

谢谢 !!!对于背景属性,在选择器之间添加选择器,而不是直接使用矢量可绘制的方法来工作,适用于棒棒糖之前的api(19)。
ANKUR

就我而言,这仍然不适用于API(16),甚至用selector
mochadwi

1

我们尝试了3件事

vectorDrawables.useSupportLibrary = true

在Application类中设置setCompatVectorFromResourcesEnabled

static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

并使用 app:srcCompat

但是即使那样,它还是失败了

Resources$NotFoundException: File res/drawable/$my_icon__0.xml from color state list resource ID #0x7f080008

然后我们发现我们的SVG具有渐变标签。对于低于API <= 23并使用相同的SVG API> = 24的情况,将渐变标签转换为单独的路径是可行的。

从此答案获得帮助https://stackoverflow.com/a/47783962/2171513


我不知道为什么没人支持这个,但这实际上可以解决我的问题。谢谢
DevMike01

0

只需将可绘制的矢量重叠到状态列表即可解决问题

例如,您有后退箭头矢量图像:

ic_back_arrow.xml

是的,您应该将其与图层列表xml(ic_back_arrow_vector_vector.xml)重叠:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/ic_back_arrow"/>
</layer-list>

因为逻辑:

vectorDrawables.useSupportLibrary = true

AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);

不会在某些中国设备和较旧的三星设备上为您提供帮助。如果您不重叠它们,它将失败。


0

我为此苦苦挣扎了好几个小时。

我尝试了所有这些答案告诉我的一切,但我的应用没有停止崩溃。我删除了这一行:app:srcCompat="@drawable/keyboard"我的应用停止崩溃了。然后当我又添加了同样的东西时,它又开始崩溃了。所以我决定打开该文件,并且在第一行看到一个错误

“可绘制的'键盘'在基本可绘制文件夹中没有声明;这可能导致崩溃。

我右键单击该文件,然后单击“在资源管理器中显示”,它不是在drawable文件夹中,而是在drawable-v24目录中。因此,我将其复制并粘贴到drawable目录中,最后摆脱了崩溃。


-2

Guilherme P的建议对我不起作用。我继续做出决定,在需要做app:srcCompat之外的事情的地方使用png,即drawableLeft,drawableRight等。这很容易进行更改,并且没有潜在的内存问题AppCompatDelegate.setCompatVectorFromResourcesEnabled(真正); 介绍。


-3

Benny的答案的另一种选择是创建一个Activity超类:

public abstract class VectorDrawableActivity extends AppCompatActivity {
  static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
  }

  //...
}

现在扩展VectorDrawableActivity而不是AppCompatActivity


@cesards为什么不呢?
法学徒
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.