For part of my applications I wanted to load an image into an activity. Based on the images main colors, I wanted to adjust the UI of the activity. Loading of the image is the easy part. This can be done via a number of libraries. At the time of writing, the most prominent libraries are: Picasso and Glide. Lately however, there is a new library which targets Kotlin specifically: Coil (see coil-kt.github.io/coil/).
I was an avid user of Glide in my projcet before, but I became somehow tired of it (especially GlideModules). And since I am curious I wanted to try something new: lets use Coil.
However, to fit my requirements, I need a way to extract the colors of the loaded images in order to align the UI colors with the colors from the loaded image. Googles term for most prominent colors is Palette
. And since the palette functionality is provided by Google Android Platte Library, the only change required is gathering the source bitmap for palette creation. With using Glide, this can be done using a request listener or even a dedicated library. For Coil, I did not find a libray and no request listeners. Instead, Coil offers Transformations
.
The idea is simple and always the same - no matter which library you are using:
The following snippet can be placed anywhere in the source code. I currently use it in my abstract base activity class, all activities in my application inherit from. It can therefor directly access parts of the layout and I do not need to pass those reference to the transformation. Another idea would be to place it somewhere separate. All references to the ImageView, the url to be loaded and the layout parameters to be altered would be needed to be passed to the function. Another solution could include returning the palette. As you can see below, I chose dirtiest, but quickest solution.
banner.load(url) {
transformations(object: Transformation {
override fun key() = "paletteTransformer"
override suspend fun transform(pool: BitmapPool, input: Bitmap): Bitmap {
val p = Palette.from(input).generate()
toolbar_layout.setStatusBarScrimColor(p.getDarkVibrantColor(0))
toolbar_layout.setExpandedTitleTextAppearance(R.style.text_title)
val swatch = p.vibrantSwatch
if (swatch != null) {
toolbar_layout.setContentScrimColor(swatch.rgb)
toolbar_layout.setCollapsedTitleTextColor(swatch.titleTextColor)
}
return input
}
})
}
Some details:
url
into and ImageView (i.e. banner is an ImageView)Transformation
which will handle our intended use caseTransformation
which I need to override and we assign a unique name to the transformer. This key can contain any information you deem necessary. It must be unique.Palette
object.As you can see, the change is really short and really simple. In my app, the image is loaded and the colors of the toolbar are set dynamically based on the image shown. Since the color palette for the movies differs, the toolbar color also changes. Star Wars and Captain Marvel were chosen as an example. Their color palette is not hugely different - but you can see the result.
This is what the final product looks like: