如何在Android API低于21的情况下使用VectorDrawables?

77

我正在开发一个Android项目,并选择使用<vector>来显示图标,因为它是适配和动态的,但是我只能在运行Android系统API版本21或更高版本的设备上运行此应用程序。我的问题是如何在低版本的Android系统(例如API 14或类似版本)上使用<vector>。谢谢!

<!-- drawable/ic_android_debug_bridge.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:height="48dp"
    android:width="48dp"
    android:viewportWidth="24"
    android:viewportHeight="24">
    <path android:fillColor="@color/primaryColorDark"
        android:pathData="M15,9A1,1 0 0,1 14,8A1,1 0 0,1 15,7A1,1 0 0,1 16,8A1,1 `0 0,1 15,9M9,9A1,1 0 0,1 8,8A1,1 0 0,1 9,7A1,1 0 0,1 10,8A1,1 0 0,1 9,9M16.12,4.37L18.22,2.27L17.4,1.44L15.09,3.75C14.16,3.28 13.11,3 12,3C10.88,3 9.84,3.28 8.91,3.75L6.6,1.44L5.78,2.27L7.88,4.37C6.14,5.64 5,7.68 5,10V11H19V10C19,7.68 17.86,5.64 16.12,4.37M5,16C5,19.86 8.13,23 12,23A7,7 0 0,0 19,16V12H5V16Z" /></vector>

如何使用向量的实际信息 - https://dev59.com/Hpzha4cB1Zd3GeqPHp7S - Maksim Ostrovidov
13个回答

101

通过支持库23.2,向下兼容到API v7的矢量图形支持已得到真正的提供。建议通过添加以下代码来禁用之前在构建期间呈现PNG的旧版本的支持库。

// Gradle Plugin 2.0+
 android {
   defaultConfig {
     vectorDrawables.useSupportLibrary = true
    }
 }

build.gradle 文件。

实现起来很简单。只需在Drawable上使用新的srcCompat属性(在app命名空间下):

<ImageView
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  app:srcCompat="@drawable/ic_add" />    // <= this is new

矢量图形可在TextView的drawableLeft属性等情况下使用。

来源:库公告

然而,我仍然建议使用Iconics库AndroidSVG或其他字体图标或SVG解决方案以获得完整的SVG标准矢量支持。


4
你如何在程序中实现这个? - Mark13426
1
如果有人在使用android:drawableLeft时遇到了崩溃问题,可以尝试以下解决方法:https://dev59.com/klsW5IYBdhLWcg3w8q_2#40523623 - Yazon2006
1
是的,我爱你。开玩笑的,这是完美的解决方案,谢谢!如果您要使用它,请注意 app:srcCompat != android:srcCompat,您必须在此处使用 app: 前缀。 - Machado

97

矢量图形(VectorDrawable)通过支持库得到了在Lollipop之前的支持,但是使用它们的方式取决于您所拥有的支持库版本,而且在某些情况下可能无法正常工作。

我制作了这张图表来帮助您(适用于Support Library 23.4.0至少到25.1.0)。

矢量图形备忘单


3
这是迄今为止最好的回答。 - Bob Liberatore
1
很遗憾,构建时的PNG生成不支持对其他资源的引用,如果您在矢量可绘制对象中使用像android:fillColor="@color/dialog_button_text"这样的内容,将会导致构建失败(因此,不使用支持库会比仅仅多花费几KB更加代价高昂)。错误信息指向http://developer.android.com/tools/help/vector-asset-studio.html以获取详细信息。 - Nolan Amy

44

我找到了解决方案!对于那些在TextView和其他“android”命名空间属性中寻找解决方案的人,这是首要的:

android {  
   defaultConfig {  
     vectorDrawables.useSupportLibrary = true  
    }  
 }

并在application类中定义如下:

    @Override
    public void onCreate() {
        super.onCreate();
        AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
    }

现在你可以使用app:srcCompat="@drawable/ic_add",但如果尝试使用android:background=android:drawableLeft=,它会导致应用程序崩溃并显示“Error inflating”异常。

我们可以创建一个被包装的drawable ic_add_wrapped.xml来解决这个问题:

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

现在它将适用于任何属性,例如drawableLeft或background。只需设置 android:drawableLeft="@drawable/ic_add_wrapped.xml"。 警告!这是一种解决方法,请自行承担风险。


它能在所有的Android版本上运行吗?包括旧版的吗?此外,它是否生成“ic_add”作为图像?如果是这样,那么使用矢量的意义就被忽略了。 - android developer
是的,这就是为什么你不应该使用你所写的代码。最好拥有额外的PNG文件,而不是因为使用这个未完成和有缺陷的支持库代码而在设备上崩溃,该代码还缺少许多基本操作。 - android developer
1
@androiddeveloper 最好不要使用未完成和有漏洞的Android操作系统。 - Yazon2006
同时也请避免使用不推荐的特殊调用“AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)” - android developer
1
layer-list 包装技巧在远程视图(通知、应用小部件)中不起作用,这是有道理的 :-)。 - Pierre-Luc Paour
显示剩余17条评论

31

矢量图现在具有向后兼容性,只需将gradle版本升级到1.4.0-beta3或更高版本,并升级您的IDE,即可实现。

我们很高兴为您的Android Studio 1.4提供矢量图资产的向后兼容性。一旦在res/drawable中拥有vectorDrawable图像,Gradle插件将在构建过程中自动生成适用于API级别20及以下的光栅PNG图像。这意味着您只需要更新和维护应用程序项目的矢量资产,而Android Studio可以处理图像转换过程。

http://android-developers.blogspot.com.uy/2015/09/android-studio-14.html


54
这并不完全正确。它只适用于imageView,对于其余部分,在旧版的Android上它将会崩溃。 - android developer
@androiddeveloper,是否有解决方案可以使其适用于其他视图,例如EditText和Buttons? - Red M
5
是的,但仅限于代码(Java/kotlin)中。不要在XML中使用(任何类型),因为这可能会导致崩溃。要通过代码获得支持库的VectorDrawable,请使用 AppCompatResources.getDrawable。不要使用 ResourcesCompatContextCompat。在此阅读更多信息:https://dev59.com/61gQ5IYBdhLWcg3wSh91#48237058 - android developer

20

如果你使用的是Android Studio,则需要使用Android Support Repository 30+,如果使用Eclipse,则需要Android support library 23.2.1+。

如果使用的是版本2.0+,请检查你的build.gradle(project)文件,并在build.gradle(app)中添加以下代码。

// Gradle Plugin 2.0+  
 android {  
   defaultConfig {  
     vectorDrawables.useSupportLibrary = true  
    }  
 }

并且:如果您使用的是版本1.5,请在您的build.gradle(应用程序)中添加以下内容。

// Gradle Plugin 1.5  
 android {  
   defaultConfig {  
     generatedDensities = []  
  }  

  // This is handled for you by the 2.0+ Gradle Plugin  
  aaptOptions {  
    additionalParameters "--no-version-vectors"  
  }  
 }  

这是使用向量图标的示例代码:

<ImageView  
  android:layout_width="wrap_content"  
  android:layout_height="wrap_content"  
  app:srcCompat="@drawable/ic_add"
  tools:ignore="MissingPrefix" />
或者
<ImageButton
  android:layout_width="wrap_content"
  android:background="@android:color/transparent"
  app:srcCompat="@drawable/camera"
  tools:ignore="MissingPrefix"
  android:layout_height="wrap_content"/>

矢量图也适用于类似 TextView 的 drawableLeft 属性。但它只适用于 API 22+,我仍然不知道它如何适用于低版本的 API。

此外,请注意如果您想兼容 API 21 及以下版本:

  • 您不能在 xml 中使用 android:background 属性或 View.setBackgroundResource() 函数。您需要使用 View.setBackground()
  • 您不能在 StateListDrawable xml 或其他 xml drawable 中使用 svg。您需要通过编程方式生成它们。
  • 通知中不能使用 svg。

3
对于 TextView,它会崩溃。 - android developer
@androiddeveloper 这是您需要的链接:https://dev59.com/klsW5IYBdhLWcg3w8q_2#40523623 - Yazon2006
完整的答案:)这正是我所期待的。 - Ashu Kumar
老兄,你真是太棒了,帮我节省了把所有的SVG文件都转换成PNG文件的时间,非常感谢。 - dave o grady

19

当您需要在程序中动态添加由SVG创建的VectorDrawable时,可以按照以下方式执行:

icon = VectorDrawableCompat.create(resources, R.drawable.ic_map_black_24dp, null)

等一下,这意味着我们可以在项目中使用SVG文件?不需要在IDE中将它们转换为VectorDrawable吗? - android developer
当然,我们需要。R.drawable.ic_map_black_24dp 这里是SVG源代码转换的结果。 - cVoronin
以上片段中的资源参数是什么? - CodingBruceLee

9

为了兼容低版本,

  1. add the below in gradle,

    android {  
       defaultConfig {  
         vectorDrawables.useSupportLibrary = true  
        }  
     }
    
  2. add the below code in onCreate() in your application class,

    @Override
        public void onCreate() {
            super.onCreate();
            AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
        }
    
  3. In xml for imageView,

    <ImageView
        android:id="@+id/imageViewMessage"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@color/transparent"
        app:srcCompat="@drawable/ic_success"/>
    
  4. If you want to change the image source programmatically use this,

    imageView.setImageResource(R.drawable.ic_launcher);
    

AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); 这个必须吗? - Akshay Shah
关于 EditText,如果我想使用 drawableStart 怎么办? - Pranav Karnik

4

我遇到了一个问题,我的矢量图像会显示出来,但是完全是黑色的,这是由于在矢量xml文件中不能引用颜色资源所致。

所以,你必须使用实际的颜色,而不是@color/primaryColorDark,例如#212121


2

您可以通过编程的方式来设置drawableLeft到您的editText或者textView中。

例如:

Drawable tick_drawable = VectorDrawableCompat.create(getResources(), R.drawable.green_tick, null);
    if (tick_drawable != null) {
        tick_drawable.setBounds(0, 0, tick_drawable.getIntrinsicWidth(),tick_drawable.getIntrinsicHeight());
    }

像这样向左绘制..
editText.setCompoundDrawables( tick_drawable , null, null, null );

在Android 5.1上获取tick_drawable的值为null。 - Ram

2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接