在前Lollipop崩溃时使用Android矢量Drawables

时间:2016-04-26 14:04:31

标签: android vector android-support-library android-drawable android-compatibility

我在Lollipop 之前的android 中使用了vector drawables,这些是我的一些库和工具版本:

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

我在应用级Build.Gradle

中添加了此属性
android {  
  defaultConfig {  
    vectorDrawables.useSupportLibrary = true  
   }  
}

还值得一提的是,我使用了一个额外的drawable,如Android官方博客(link here)中所述的LayerDrawable(layer_list),用于设置app:srcCompat之外的矢量绘图的drawables

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

你会发现直接引用外面的矢量绘图   app:srcCompat将在Lollipop之前失败。但是,AppCompat确实如此   支持在另一个引用它们时加载矢量drawable   可绘制容器,如StateListDrawable,InsetDrawable,   LayerDrawable,LevelListDrawable和RotateDrawable。通过使用这个   间接,您可以在TextView的情况下使用矢量drawable   android:drawableLeft属性,通常不能   支持矢量绘图。

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

android:background
android:drawableLeft
android:drawableRight
android:drawableTop
android:drawableBottom
在Lollipop之前的ImageViewImageButtonTextViewEditText上,它会引发预期:

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

16 个答案:

答案 0 :(得分:65)

我认为这是因为支持向量在最新的库版本中被禁用:23.3.0

根据POST

  

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

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

  

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

我有类似的问题。因此,在我的情况下,我将所有使用矢量绘制的图标从资源恢复为PNG图像(因为即使在他们提供再次启用它的选项后,内存问题也会继续发生)。

我不确定这是否是最好的选择,但它确定了我认为的所有崩溃。

<强>更新

他们重新启用了VectorDrawable Android Support Library 23.4.0

  

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

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

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

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

    ...
}

答案 1 :(得分:56)

我遇到了同样的问题。 但做了很多R&amp; D我得到了答案。

对于Imageview和ImageButton使用,app:srcCompat="@drawable/...." 对于像Button,Textview这样的其他视图,而不是在XML中使用"drawableLeft/right...",请将programable规定为:

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

使用“AppCompatResources”获取drawable。

答案 2 :(得分:47)

详细说明其他very good answers,这里有a diagram可以帮助您。如果您的支持库从23.4.0到至少25.1.0,则有效。

VectorDrawable cheatsheet

答案 3 :(得分:36)

Guillherme P 的答案非常棒。只是为了做一个小的改进,你不需要在每个活动中添加那一行,如果你在Application类中添加它一次也可以。

android {
  defaultConfig {
    vectorDrawables.useSupportLibrary = true
  }
}

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

app:srcCompat

此外,当Google添加对VectorDrawables(release note)的Drawable Containers的支持时,请确保您使用的支持库版本大于v23.4

<强>更新

代码更改:

  1. 请务必更新android:src每个接受<bitmap>属性的地方(如果drawableLeft标记无效,IDE会向您发出警告)。
  2. 对于drawableStart和类似视图中使用的drawableRightdrawableEndTextViewdrawableStart属性,您必须以编程方式设置它们现在。设置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); }

    的示例
    {{1}}

答案 4 :(得分:12)

我遇到了同样的问题。并通过删除

来解决它
vectorDrawables.useSupportLibrary = true

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

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

答案 5 :(得分:8)

预棒棒糖上的VectorDrawables可以在不使用

的情况下正常工作
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);

如果你想在ImageViews中使用VectorDrawables,你可以使用属性srcCompat它可以工作,但在Buttons或TextViews中它不会,所以你需要包装可绘制为InsetDrawable或LayerDrawable。我发现了另一个技巧,如果你使用数据绑定,你可以这样做:

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

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

答案 6 :(得分:5)

经过大量的研发,最终获得了解决此问题的解决方案,以解决棒棒糖前置设备上的崩溃问题。

对于Imageview

  
      
  • 使用 app:srcCompat 代替android:src
  •   

对于TextView / EditText

  
      
  • 删除 drawableleft drawableright ....并从可绘制的Java代码中进行设置。
  •   
     

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

对于Build.gradle

  

vectorDrawables.useSupportLibrary = true

答案 7 :(得分:4)

对于升级到android gradle 3.0及更高版本的任何人,无需使用AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)或设置vectorDrawables.useSupportLibrary = true(添加此项会导致问题)并使用app:srcCompat,它只是的工作原理。

我花了两天时间搞清楚这一点,并且在google的文档中找不到任何相关的文档......

答案 8 :(得分:2)

我在Pre-lollipop设备上使用VectorDrawables,这就是我的方法: -

第1步: 把它放在你的app level gradle中。

android {
  defaultConfig {
    vectorDrawables.useSupportLibrary = true
  }
}

第2步:

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

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

第3步:

使用

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

答案 9 :(得分:1)

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

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

出现错误

“ drawable'Keyboard'在基本drawable中没有声明 夹;这可能会导致崩溃。

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

答案 10 :(得分: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);

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

答案 11 :(得分:0)

最简单的使用方式:

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

然后... 只需使用app:**为了兼容性而兼容

还添加了对buil.gradle(模块)的支持

android {
 defaultConfig {
vectorDrawables.useSupportLibrary = true
               }
        }

答案 12 :(得分:0)

使用以下代码后。

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"
       />

答案 13 :(得分:0)

我们尝试了三件事

vectorDrawables.useSupportLibrary = true

在应用程序类中设置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

的帮助

答案 14 :(得分:-2)

Guilherme P的建议不适合我。我继续做下决定使用png,我需要在app之外做一些事情:srcCompat,即drawableLeft,drawableRight等。这是一个非常简单的改变,并没有潜力内存问题AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);  介绍。

答案 15 :(得分:-3)

Benny的答案的替代方法是创建Activity超类:

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

  //...
}

现在扩展VectorDrawableActivity而不是AppCompatActivity