AppCompat 23.2 在 API<21 上将 VectorDrawableCompat 与 RemoteViews (AppWidget) 结合使用

AppCompat 23.2 use VectorDrawableCompat with RemoteViews (AppWidget) on API<21

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

为了减小我的应用程序 APK 大小,我不想为旧 API 平台添加我的可绘制对象的替代 PNG 版本。

我该怎么做?

2017 年 10 月 22 日更新

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

2016 年 5 月 9 日更新

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

Lollipop 之前的 VectorDrawable 和 RemoteViews

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

TintResources AppCompatDrawableManager ContextCompat 是 class,在 Lollipop 之前的设备上,解析 VectorDrawables XML 文件并将它们转换为VectorDrawableCompat 个可以一直使用的实例 API 7.

然后,一旦你有了一个 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:srcapp:srcCompat 都不起作用)。您必须以编程方式设置它们。

在您的 AppWidgetProvider class 中根据 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);
}


参考资料

以下方法会将 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;
}