在API<21上使用RemoteViews(AppWidget)时,AppCompat 23.2使用VectorDrawableCompat。

32
我有一个AppWidget,想要在其中使用VectorDrawables,包括在Lollipop之前的设备上。 VectorDrawableCompat无法与我创建的RemoteViews一起使用。
为了让我的应用程序APK大小保持不变,我不想为旧的API平台添加可替代的PNG版本的drawables。
我该怎么做?
2个回答

54

更新于 2017年10月22日

正如 @user924 所指出的,现在 AppCompatDrawableManager 访问被限制为其自己的库。 ContextCompat.getDrawable(...) 应该能解决问题。

更新于 2016年9月5日

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

在 Lollipop 之前使用 VectorDrawable 和 RemoteViews

您可以通过使用 TintContextWrapperContextCompat 来避免添加矢量可绘制资源的替代位图版本。在早期的 Android 版本中,这个类可以解析 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);
}


参考资料


2
TintContextWrapper在android.support.v7.widget中不是公共的,无法从包外访问。 - Kirill Kulakov
1
AppCompatDrawableManager can only be called from within the same library group - user924
嗨,@user924,我更新了答案,以添加对最新的Android支持库版本的兼容性!谢谢! - araks
{btsdaf} - user924
1
@user924,RemoteViews肯定不能与AppCompatImageView一起使用。您可以在其文档中定义的小部件和布局列表中使用RemoteViews。 - Daniel
显示剩余2条评论

8
以下方法会在之前将矢量图转换为位图,这应该可以解决问题。
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;
}

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