31

我有一个 AppWidget,我也想在棒棒糖之前的设备上使用 VectorDrawables。VectorDrawableCompat 不适用于我创建的 RemoteViews。

为了减小我的应用 APK 大小,我不想为旧 API 平台添加我的 drawable 的替代 PNG 版本。

我怎样才能做到这一点?

4

2 回答 2

53

更新 22/10/2017

正如@user924 所指出的,现在AppCompatDrawableManager访问仅限于其自己的库。 ContextCompat.getDrawable(...)应该可以解决问题。

更新 05/09/2016

正如@kirill-kulakov 在其回答中指出的那样,支持库的最新更新将 TintContextWrapper 的可见性限制在它自己的包中。我正在更新我的答案以删除不正确的代码,但请感谢 Kirill 的更正!

VectorDrawable 和 RemoteViews pre-Lollipop

您可以通过简单的技巧避免添加矢量可绘制资源的替代光栅化版本使用AppCompat TintResources通过TintContextWrapper 使用AppCompatDrawableManager使用ContextCompat

TintResources AppCompatDrawableManager ContextCompat是在棒棒糖之前的设备上解析VectorDrawable的 XML 文件并将它们转换为可一直使用到 API 7 的VectorDrawableCompat实例的类。

然后,一旦你有一个VectorDrawableCompat实例,就将它光栅化到一个位图上。稍后您将在远程ImageView中使用此位图。


开始之前:AppCompat 库

确保您使用的是 Android Studio 2.0+ 并已build.gradle按如下方式配置您的应用文件:

android {
  defaultConfig {
    vectorDrawables.useSupportLibrary = true
  }
}

dependencies {
  compile 'com.android.support:appcompat-v7:23.3.0'
}


更新您的 AppWidgetProvider

首先:不要在你的RemoteViews布局文件中设置你的矢量可绘制资源(既不工作android:src也不行app:srcCompat)。您必须以编程方式设置它们。

在您的AppWidgetProvider类中,根据 API 级别设置矢量资源或光栅化版本:

RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.appwidget_layout);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
  remoteViews.setImageViewResource(R.id.imageView, R.drawable.vector);

} else {
  Drawable d = ContextCompat.getDrawable(context, R.drawable.vector);
  Bitmap b = Bitmap.createBitmap(d.getIntrinsicWidth(),
                                 d.getIntrinsicHeight(),
                                 Bitmap.Config.ARGB_8888);
  Canvas c = new Canvas(b);
  d.setBounds(0, 0, c.getWidth(), c.getHeight());
  d.draw(c);
  remoteViews.setImageViewBitmap(R.id.imageView, b);
}


参考

  • ContextCompat源代码
  • Chris Banes 的AppCompat v23.2 - 向量时代博客文章介绍了VectorDrawableCompat并解释了 AppCompat 用来使它们在棒棒糖之前的设备上工作的技巧。
于 2016-02-25T16:50:26.133 回答
8

以下方法将vector drawable之前转换为位图,这应该可以解决问题。

public static BitmapDrawable vectorToBitmapDrawable(Context ctx, @DrawableRes int resVector) {
    return new BitmapDrawable(ctx.getResources(), vectorToBitmap(ctx, resVector));
}

public static Bitmap vectorToBitmap(Context ctx, @DrawableRes int resVector) {
    Drawable drawable = AppCompatDrawableManager.get().getDrawable(ctx, resVector);
    Bitmap b = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
    Canvas c = new Canvas(b);
    drawable.setBounds(0, 0, c.getWidth(), c.getHeight());
    drawable.draw(c);
    return b;
}
于 2016-05-08T08:10:11.560 回答