I don't get how, given an AdaptiveIconDrawable instance, launchers change the shape.
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.
I don't have a sample project of my own, but Nick Butcher made a great sample project and series of blog posts: AdaptiveIconPlayground.
Given a AdaptiveIconDrawable instance, how do you shape it, to be of a circular shape, rectangle, rounded rectangle, tear, and so on?
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)
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.
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.
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.
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.
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
has a setIcon(Icon icon)
method where you need to pass it in. (And the same applies for the compat versions)
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
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?
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.
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
To switch between background shapes you could use anything from if/else, over composition, to inheritance, and just draw the shape you like.