在Android O预览版中将AdaptiveIconDrawable转换为位图

16

昨天发布了新的预览版,我开始更新我的应用程序到这个版本。我的应用程序的一部分是列出已安装的应用程序及其相关的图标。

Drawable drawable = mPackageManager.getApplicationIcon(packageName);

应用程序的这一部分仍然可用。类似时钟、计算器或信息等应用程序已支持新版本的图标,因此它们会返回一个AdaptiveIconDrawable

Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();

这部分已经无法使用了。是否有其他方式将 AdaptiveIconDrawable 转换为 Bitmap?提前致谢。

2个回答

40

这是更普遍适用的解决方案:

@NonNull
private Bitmap getBitmapFromDrawable(@NonNull Drawable drawable) {
    final Bitmap bmp = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
    final Canvas canvas = new Canvas(bmp);
    drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
    drawable.draw(canvas);
    return bmp;
}
它还会按照系统定义的形状渲染背景,如果您不想使用自己的形状。

您可以在任何Drawable上使用它,也可以用于VectorDrawable。它也适用于BitmapDrawable,只是getBitmap()将更加内存高效。

2
这似乎比经历“LayerDrawable”繁琐的过程更好。您还可以在函数顶部添加“if(drawable instanceof BitmapDrawable) { return ((BitmapDrawable) drawable).getBitmap(); }”以优化常见情况。 - Steve Blackwell
1
这很棒。另外,最好使用Math.max(drawable.getIntrinsicWidth(), 1)或类似的东西,因为有些可绘制对象如果没有定义大小(如颜色),则可能返回-1。 - Shchvova

9
我们可以通过以下方式实现:

AppIconHelper.java

(应用图标助手.java)
public class AppIconHelper {

    public static Bitmap getAppIcon(PackageManager mPackageManager, String packageName) {

        if (Build.VERSION.SDK_INT >= 26) {
            return AppIconHelperV26.getAppIcon(mPackageManager, packageName);
        }

        try {
            Drawable drawable = mPackageManager.getApplicationIcon(packageName);

            return ((BitmapDrawable) drawable).getBitmap();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }
}

对于支持 Android O(>= 26)的设备,我们可以调用 AppIconHelperV26 类来获取 AppIcon。在此过程中,如果其 drawable 是 AdaptiveIconDrawable,则执行以下步骤:

  1. 获取前景和背景 drawable,并将它们创建为 Layer Drawable
  2. 使用 Canvas 将 Layer drawable 转换为 Bitmap

AppIconHelperV26.java

public class AppIconHelperV26 {

    @RequiresApi(api = Build.VERSION_CODES.O)
    public static Bitmap getAppIcon(PackageManager mPackageManager, String packageName) {

        try {
            Drawable drawable = mPackageManager.getApplicationIcon(packageName);

            if (drawable instanceof BitmapDrawable) {
                return ((BitmapDrawable) drawable).getBitmap();
            } else if (drawable instanceof AdaptiveIconDrawable) {
                Drawable backgroundDr = ((AdaptiveIconDrawable) drawable).getBackground();
                Drawable foregroundDr = ((AdaptiveIconDrawable) drawable).getForeground();

                Drawable[] drr = new Drawable[2];
                drr[0] = backgroundDr;
                drr[1] = foregroundDr;

                LayerDrawable layerDrawable = new LayerDrawable(drr);

                int width = layerDrawable.getIntrinsicWidth();
                int height = layerDrawable.getIntrinsicHeight();

                Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);

                Canvas canvas = new Canvas(bitmap);

                layerDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
                layerDrawable.draw(canvas);

                return bitmap;
            }
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }

        return null;
    }
}

现在您可以调用AppIconHelper.getAppIcon获取位图, AppListAdapter.java
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    //... your code here
    Bitmap appIcon = AppIconHelper.getAppIcon(packageManager, packageName);
    imageView.setImageBitmap(appIcon);

}

1
这是一个相当不错的解决方案,只是它不能像AdaptiveIconDrawable本身那样将背景圆角化。 - ATom

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