启动器如何更改自适应图标的形状,包括删除背景? [英] How do launchers change the shape of an adaptive icon, including removal of background?

查看:173
本文介绍了启动器如何更改自适应图标的形状,包括删除背景?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

从Android O开始,应用程序可以具有自适应图标,该图标是两层可绘制对象:前景和背景.背景是一个遮罩,它会成为启动器/用户选择的形状,而操作系统也具有默认形状.

Starting from Android O, apps can have adaptive icons, which are 2 layers of drawables: foreground and a background. The background is a mask that gets to be a shape of the launcher/user's choice, while the OS has a default shape for it too.

以下是Nova Launcher允许执行的操作的示例:

Here's an example of what Nova Launcher allows to do:

如您所见,它不仅可以选择要使用的形状,而且还可以完全避免使用形状(在首选旧版图标"中).

As you can see, it allows not only to choose which shape to use, but also avoid a shape at all (in "prefer legacy icons").

以下是一些链接:

  • https://www.youtube.com/watch?v=5MHFYfXno9c
  • https://medium.com/@ianhlake/vectordrawable-adaptive-icons-3fed3d3205b5

虽然我知道如何创建 AdaptiveIconDrawable 实例,并且我知道可以帮助为当前应用创建一个实例的向导,但在AdaptiveIconDrawable实例的情况下,启动器如何改变形状,我不知道.

While I know how to create a AdaptiveIconDrawable instance, and I'm aware of the wizard that helps creating one for the current app, I don't get how, given an AdaptiveIconDrawable instance, launchers change the shape.

不仅如此,我还记得我看到一两个发射器,它们没有任何形状.

Not only that, but I remember I saw a launcher or two that allows to not have any shape.

可悲的是,我找不到有关此部分的任何信息,可能是因为这是一个相对较新的功能.在StackOverflow上甚至没有关键字.

Sadly I can't find any information about this part, maybe because this is a relatively very new feature. There isn't even a keyword for it here on StackOverflow.

我尝试阅读有关自适应图标的信息,但是找不到对接收方的引用.

I tried reading about adaptive icons, but couldn't find a reference to the receiver side.

我知道其中包含2个可绘制对象:

I know it has the 2 drawables within it:

  • https://developer.android.com/reference/android/graphics/drawable/AdaptiveIconDrawable.html#getBackground()
  • https://developer.android.com/reference/android/graphics/drawable/AdaptiveIconDrawable.html#getForeground()

至少,我知道如何从第三方应用程序中获取AdaptiveIconDrawable实例(假设它有一个):

I know, at least, how to get an AdaptiveIconDrawable instance out of a third party app (assuming it has one) :

PackageManager pm = context.getPackageManager();
Intent launchIntentForPackage = pm.getLaunchIntentForPackage(packageName);
String fullPathToActivity = launchIntentForPackage.getComponent().getClassName();
ActivityInfo activityInfo = pm.getActivityInfo(new ComponentName(packageName, fullPathToActivity), 0);
int iconRes = activityInfo.icon;
Drawable drawable = pm.getDrawable(packageName, iconRes, activityInfo.applicationInfo); // will be AdaptiveIconDrawable, if the app has it

问题

  1. 给出一个AdaptiveIconDrawable实例,如何将其成形为圆形,矩形,圆角矩形,撕裂等?

  1. Given a AdaptiveIconDrawable instance, how do you shape it, to be of a circular shape, rectangle, rounded rectangle, tear, and so on?

如何删除形状并仍然具有有效的图标尺寸(使用其前景中的可绘制对象)?启动器的应用程序图标的官方大小为48 dp,而AdaptiveIconDrawable内部可绘制对象的官方图标大小为72dp(前景),108dp(背景).我想这意味着获取前景可绘制对象,以某种方式调整其大小,然后转换为位图.

How do I remove the shape and still have a valid size of the icon (using its foreground drawable in it) ? The official size of an app icon for launchers is 48 dp, while the official ones for AdaptiveIconDrawable inner drawables are 72dp (foreground), 108dp (background). I guess this would mean taking the foreground drawable, resize it somehow, and convert to a bitmap.

在哪种情况下,使用IconCompat.createWithAdaptiveBitmap()有用吗?写道:如果要使用位图构建动态快捷方式,则可能会发现支持库26.0.0-beta2的IconCompat.createWithAdaptiveBitmap()有助于确保正确屏蔽位图以匹配其他自适应图标." ,但我不知道它对哪种情况有用.

In which case exactly is it useful to use IconCompat.createWithAdaptiveBitmap() ? It was written that "If you’re building a dynamic shortcut using a Bitmap, you might find the Support Library 26.0.0-beta2’s IconCompat.createWithAdaptiveBitmap() useful in ensuring that your Bitmap is masked correctly to match other adaptive icons." , but I don't get which cases it's useful for.


为了在自适应图标的前景部分之外创建一个位图,同时将其调整为适当的大小,我认为这可能是一个很好的解决方案:


In order to create a bitmap out of the foreground part of the adaptive icon, while resizing to a proper size, I think this could be a good solution:

val foregroundBitmap = convertDrawableToBitmap(drawable.foreground)
val targetSize = convertDpToPixels(this, ...).toInt()
val scaledBitmap = ThumbnailUtils.extractThumbnail(foregroundBitmap, targetSize, targetSize, ThumbnailUtils.OPTIONS_RECYCLE_INPUT)

fun convertDrawableToBitmap(drawable: Drawable?): Bitmap? {
    if (drawable == null)
        return null
    if (drawable is BitmapDrawable) {
        return drawable.bitmap
    }
    val bounds = drawable.bounds
    val width = if (!bounds.isEmpty) bounds.width() else drawable.intrinsicWidth
    val height = if (!bounds.isEmpty) bounds.height() else drawable.intrinsicHeight
    val bitmap = Bitmap.createBitmap(if (width <= 0) 1 else width, if (height <= 0) 1 else height,
            Bitmap.Config.ARGB_8888)
    val canvas = Canvas(bitmap)
    drawable.setBounds(0, 0, canvas.width, canvas.height)
    drawable.draw(canvas)
    drawable.bounds = bounds;
    return bitmap
}

fun convertDpToPixels(context: Context, dp: Float): Float = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.resources.displayMetrics)

也许可以避免同时拥有2个位图,但这是可以的.

Might be able to avoid having 2 bitmaps at the same time, but this is ok I think.

关于各种形状的可绘制对象的创建,我仍然不确定该怎么做.我在以下答案中看到的唯一解决方案是使用圆角矩形或圆形,但是想到的还有其他形状(例如眼泪).

About the creation of a shaped drawable of various types, I'm still not sure how to do it. Only solution I've seen by the answers below is of using a rounded rectangle or a circle, but there are other shapes (for example the tear) that can come to mind.

谷歌(这里)告诉我,我应该使用 AdaptiveIconDrawable.getIconMask() ,但是我没有得到任何进一步的信息.但是,我找到了一篇关于此这里.

I was told as some point by Google (here) that I should use AdaptiveIconDrawable.getIconMask(), but I wasn't given any further information. However, I've found a nice article about this here.

推荐答案

在给定AdaptiveIconDrawable实例的情况下,我不知道启动器如何改变形状.

I don't get how, given an AdaptiveIconDrawable instance, launchers change the shape.

Launcher只是应用程序,因此他们只需以所需形状(或用户选择的形状)绘制背景,然后在顶部绘制前景.

Launchers are just apps, so they simply draw the background in the shape they want (or the user selected) and then draw the foreground on top.

我没有自己的示例项目,但是Nick Butcher做了一个很棒的示例项目,并发布了一系列博客文章:

I don't have a sample project of my own, but Nick Butcher made a great sample project and series of blog posts: AdaptiveIconPlayground.

给出一个AdaptiveIconDrawable实例,如何将其成形为圆形,矩形,圆角矩形,撕裂等?

Given a AdaptiveIconDrawable instance, how do you shape it, to be of a circular shape, rectangle, rounded rectangle, tear, and so on?

最简单的方法是光栅化可绘制对象并使用着色器绘制位图,就像在尼克的 AdaptiveIconView :

The simplest way is to rasterize the drawable and draw the bitmap using a shader like it is done in Nick's AdaptiveIconView:

private val backgroundPaint = Paint(Paint.ANTI_ALIAS_FLAG)
private val background: Bitmap

// ...

background = Bitmap.createBitmap(layerSize, layerSize, Bitmap.Config.ARGB_8888)
backgroundPaint.shader = BitmapShader(background, CLAMP, CLAMP)

// < rasterize drawable onto `background` >

// draw desired shape(s)
canvas.drawRoundRect(0f, 0f, iconSize.toFloat(), iconSize.toFloat(),
                cornerRadius, cornerRadius, backgroundPaint)

如何删除形状并仍然具有有效的图标大小(使用其前景中的可绘制对象)?启动器的应用程序图标的官方大小为48 dp,而AdaptiveIconDrawable内部可绘制对象的官方图标大小为72dp(前景),108dp(背景).我想这意味着获取前景可绘制对象,以某种方式调整其大小,然后转换为位图.

How do I remove the shape and still have a valid size of the icon (using its foreground drawable in it) ? The official size of an app icon for launchers is 48 dp, while the official ones for AdaptiveIconDrawable inner drawables are 72dp (foreground), 108dp (background). I guess this would mean taking the foreground drawable, resize it somehow, and convert to a bitmap.

如果您不想要背景,请不要绘制背景.您完全可以控制.大小并不重要,因为您通常知道应该绘制多大的图标.文档指出前景和背景应该为108dp,因此您可以简单地缩小图形尺寸.如果前景/背景使用矢量图形,则大小实际上并不重要,因为您可以按自己的喜好绘制它们.

If you don't want a background, just don't draw it. You're in full control. The size does not really matter, because you usually know how big your icons should be drawn. The documentation states that foreground and background should be 108dp, so you can simply downscale your drawing. If foreground/background use vector graphics, then size really does not matter, as you can just draw them however big you like.

如果您对前景进行栅格化,则可以如上所示进行自定义绘制,或选择Canvas#drawBitmap(...),它还提供了多个选项来绘制位图,包括传递变换矩阵或仅提供一些边界.

If you rasterize the foreground, then you can do custom drawing as seen above, or choose Canvas#drawBitmap(...), which also offers multiple options to draw a Bitmap, including to pass in a transformation matrix, or simply some bounds.

如果不对可绘制对象进行栅格化,则也可以使用drawable.setBounds(x1, y1, x2, y2),在其中可以设置可绘制对象应绘制自身的边界.这也应该起作用.

If you don't rasterize your drawable you can also use drawable.setBounds(x1, y1, x2, y2), where you can set the bounds on where the drawable should draw itself. This should also work.

在哪种情况下,使用IconCompat.createWithAdaptiveBitmap()到底有用吗?写道:如果要使用位图构建动态快捷方式,则可能会发现支持库26.0.0-beta2的IconCompat.createWithAdaptiveBitmap()有助于确保正确屏蔽位图以匹配其他自适应图标." ,但我不知道它对哪种情况有用.

In which case exactly is it useful to use IconCompat.createWithAdaptiveBitmap() ? It was written that "If you’re building a dynamic shortcut using a Bitmap, you might find the Support Library 26.0.0-beta2’s IconCompat.createWithAdaptiveBitmap() useful in ensuring that your Bitmap is masked correctly to match other adaptive icons." , but I don't get which cases it's useful for.

ShortCutInfo.Builder 有一个setIcon(Icon icon)方法,您需要在其中传递它.(兼容版本也是如此)

ShortCutInfo.Builder has a setIcon(Icon icon) method where you need to pass it in. (And the same applies for the compat versions)

似乎Icon用于控制作为图标传入的位图的类型.现在,我找不到Icon的其他用途.我认为您在创建启动器时不会使用它.

It seems that Icon is used to have control over the kind of Bitmap that gets passed in as an icon. Right now I could not find any other usage for Icon. I don't think that you would use this when creating a launcher.

反映最后评论的更多信息

More information reflecting the last comment

您是否用自己的drawable包装AdaptiveIconDrawable类?我只想以某种方式将其转换为可以使用的图像,同时转换为ImageView和Bitmap,并且希望使用上面屏幕快照中显示的所有形状来控制形状.我该怎么办?

Do you wrap the AdaptiveIconDrawable class with your own drawable? I just want to convert it somehow to something I can use, to both an ImageView and a Bitmap, and I wish to control the shape, using all shapes I've shown on the screenshot above. How would I do it?

如果您单击上面的链接,您会看到一个绘制AdaptiveIconDrawable的自定义AdaptiveIconView,因此绝对可以选择执行自定义视图,但是提到的所有内容都可以轻松地移至一个自定义Drawable中,然后您就可以也可以与基本的ImageView一起使用.

If you follow the links above you can see a custom AdaptiveIconView that draws the AdaptiveIconDrawable, so doing a custom view is definitely an option, but everything mentioned can be moved just as easily into a custom Drawable, which you then could also use with a basic ImageView.

您可以使用Canvas上可用的方法以及如上所示的BitmapShader来实现各种不同的背景,例如除了drawRoundRect之外,我们还有

You can achieve the various different backgrounds by using the methods available on Canvas along with a BitmapShader as shown above, e.g. additionally to drawRoundRect we would have

canvas.drawCircle(centerX, centerY, radius, backgroundPaint) // circle
canvas.drawRect(0f, 0f, width, height, backgroundPaint) // rect
canvas.drawPath(path, backgroundPaint) // more complex shapes

要在背景形状之间切换,可以使用从if/else,过度合成,继承到仅绘制所需形状的任何东西.

To switch between background shapes you could use anything from if/else, over composition, to inheritance, and just draw the shape you like.

这篇关于启动器如何更改自适应图标的形状,包括删除背景?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆