AdaptiveIconView is a library built to allow an easy implementation of pre-Oreo adaptive icon support in Android launchers. Special thanks to Lawnchair and its developers for providing the method used to access -v26 assets on pre-Oreo devices.
For demonstration purposes, sample APKs can be downloaded here.
Circles | Squircles | Teardrops |
---|---|---|
This project is published on JitPack, which you can add to your project by copying the following to your root build.gradle at the end of "repositories".
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
To add the dependency, copy this line into your app module's build.gradle file.
compile 'me.jfenn:AdaptiveIconView:0.0.1'
The Android support libraries have been refactored from android.support.*
to androidx.*
as detailed here. As such, AdaptiveIconView only uses the new dependencies. If your project still uses the older support libraries for some reason, you must compile your own version of the library (either refactoring it yourself or using a version from before the change).
The AdaptiveIcon
class contains multiple ways to load and store the assets required to pass to an AdaptiveIconView
. Most methods involve the AdaptiveIcon.Loader
subclass, which contains many customization options and several 'fallback' classes for applications passed that do not have an adaptive icon.
This method will create an asynchronous thread to load the icon for you, but you will need to properly manage it yourself to prevent memory leaks. Unless you don't care about memory leaks and just want to quickly implement something that works, in which case this is perfect for you. Coincidentally, this is the loading method that is used in the sample application.
new AdaptiveIcon.Loader()
.with(this) //always pass a context before calling any other methods
.fallback(new AdaptiveIcon.Loader.LegacyIconFallback()) //(optional) specify a fallback to use if there is no adaptive icon or if it is inaccessible to the app
.loadAsync(resolveInfo, new AdaptiveIcon.Loader.AsyncCallback() { //specify a ResolveInfo of the app to load the icon of
@Override
public void onResult(ResolveInfo info, AdaptiveIcon icon) {
//pass the loaded icon to an AdaptiveIconView
}
});
However, if you actually care about your end users at all, it would be far better to use the load(ResolveInfo)
method instead of loadAsync
and handle the multithreading spaghetti yourself. Please also note that, while it may not make a huge impact on performance, you can call load
multiple times on the same Loader
with different ResolveInfo
s instead of creating a new Loader
for every single icon that you need to load.
Ignoring the variety of different loading and fallback methods, all that the AdaptiveIcon
class really does is store drawables, bitmaps, and a scale for the adaptive icon. With this in mind, you can easily create one yourself.
AdaptiveIcon icon = new AdaptiveIcon(foregroundDrawable, backgroundDrawable, 1.0);
One thing to keep in mind here is that the scale (the third parameter passed to the constructor), for some bizarre reason, is actually reversed. Smaller numbers will make the icon larger, and larger numbers will make it smaller. Keep in mind that the scale does not affect the size of the shape of the icon, only what is displayed inside of it.
The AdaptiveIconView class should be pretty simple to use. The setIcon
and getIcon
methods set and get the AdaptiveIcon
class it uses, updating the view automatically. setPath(Rect, Path)
, or setPath(String)
(which accepts a path string within a 100x100 rect) can be used to specify a shape for the icon to clip to, but you may find it easier to use setPath(int pathType)
instead (provided types are PATH_CIRCLE
, PATH_SQUIRCLE
, PATH_ROUNDED_SQUARE
, PATH_SQUARE
, and the infamous PATH_TEARDROP
). setOffset(x, y)
can be used to quickly offset the drawables inside the icon for fancy movement animations.
By default, the view will set its own touch listener to animate the icon scale when it is clicked. This can be disabled by setting another touch listener (or just passing null). There are currently no methods to scale the icon yourself, but they should be added soon.
In Method 1, the LegacyIconFallback
is used to tell the loader to create an AdaptiveIcon
using the legacy icon if there is no adaptive icon for the specified ResolveInfo
. In addition to this, fallbacks can be chained together - you can create another fallback as a fallback for another fallback that is the fallback for the original loader - and there are many more options that have not yet been covered. Instead of going over all of the options in detail, I will just create a table for each of the fallbacks with short descriptions of each.
Method Name | Parameters | Description |
---|---|---|
withFallback | Fallback | Sets a fallback to use if there is no icon for this fallback. |
getFallback | Returns the current fallback, or null if there isn't one. | |
load | Context, ResolveInfo | Loads the icon for this fallback, or this fallback's fallback if it fails. |
Method Name | Parameters | Description |
---|---|---|
withBackgroundColor | @ColorInt int | Sets the background to a new ColorDrawable of the passed color int (defaults to the dominant color of the legacy icon). |
withBackground | Drawable | Sets the background to the passed Drawable. |
shouldClip | @Nullable Boolean | Whether legacy icons should be clipped by the shape, or null (the default value) to determine automatically. |
withScale | @Nullable Double | Specify a custom scale for legacy icons, or null (default) to determine automatically. |
shouldRemoveShadow | boolean | Whether the shadow and other transparent parts should be removed from the icon - may sometimes result in choppy edges (defaults to false). |
Method Name | Parameters | Description |
---|---|---|
withBackgroundColor | @ColorInt int | Sets the background to a new ColorDrawable of the passed color int (defaults to the dominant color of the round icon). |
withBackground | Drawable | Sets the background to the passed Drawable. |
withScale | @Nullable Double | Specify a custom scale for round icons, or null (default) to determine automatically. |
shouldRemoveShadow | boolean | Whether the shadow and other transparent parts should be removed from the icon - may sometimes result in choppy edges (defaults to false). |
This fallback has not yet been created (see issue #1), but will allow you to pass the package name of an icon pack for the loader to use.