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:src
和 app: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);
}
参考资料
- 上下文兼容性source code
- Chris Banes 的 AppCompat v23.2 - Age of the vectors 博客 post 介绍了 VectorDrawableCompat 并解释了 AppCompat 用来使它们在 Lollipop 之前的设备上工作的技巧。
以下方法会将 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;
}
我有一个 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:src
和 app: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);
}
参考资料
- 上下文兼容性source code
- Chris Banes 的 AppCompat v23.2 - Age of the vectors 博客 post 介绍了 VectorDrawableCompat 并解释了 AppCompat 用来使它们在 Lollipop 之前的设备上工作的技巧。
以下方法会将 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;
}