Colors Palette API | Selecting Colors with the Palette API in Android with Example

Good visual design is essential for a successful app, and color schemes are a primary component of design. 

The palette library is a support library that extracts prominent colors from images to help you create visually engaging apps.

Goals

  • By the end of this tutorial, the reader should:
  • Have an understanding of what Palette API is.
  • Know how to set up the Palette API library.
  • Know how to extract colors from an image using the Palette API.

What is Palette?

  • Palette is a support library in Android. It extracts prominent colors from Bitmap images. We can use it in styling view components in the app.
  • The views matche the prominent color from the image. For instance, the toolbar, background, or even text color.

Advantages of Using Palette API

  • It provides a helper class to extract prominent colors from an image.
  • We can use colors obtained to make elegant application UI designs.
  • We can customize the color Palette using in-build methods. For instance, adding filters and much more.

Set up the library

implementation 'androidx.palette:palette:1.0.0'

..

Color profiles may be extracted from images on Android using AndroidX’s Palette API; typically, color profiles would be used to generate color-coordinated widgets based on a picture. 

A card, for example, may include an image and title text that are colored in accordance with the picture’s color profiles. Palette API allows you to obtain the following color profiles:

Extract color profiles

The palette library attempts to extract the following six color profiles: 
  • Light Vibrant 
  • Vibrant Dark 
  • Vibrant Light 
  • Muted Muted 
  • Dark Muted
..
Understanding the Core
Each color profile includes a Swatch with three major colors:

code to understand the code in more

RGB: The primary color of the swatch.
titleTextColor: The color to use for the ‘title’ text that appears above the swatch’s primary color.
bodyTextColor: The color to use for the ‘body’ text that appears above the primary color of the swatch.

Here is our fragment_color_palette.xml layout xml file
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <androidx.core.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"
            android:gravity="center"
            android:paddingTop="16dp"
            android:paddingStart="16dp"
            android:paddingEnd="16dp"
            android:clipToPadding="false">


            <ImageView
                android:id="@+id/color_extraction_target_image_view"
                android:layout_width="match_parent"
                android:layout_height="200dp"
                android:src="@drawable/sample2"
                android:scaleType="centerCrop"
                android:fitsSystemWindows="true"
                app:layout_collapseMode="parallax"
                android:contentDescription="@string/app_name" />

            <TextView
                android:gravity="center"
                android:id="@+id/header_subtitle"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="5dp"
                android:text="Extract representative color palettes from images."
                android:textAppearance="?attr/textAppearanceBody2"
                android:textColor="@color/material_on_surface_emphasis_medium"/>

            <GridLayout
                android:layout_gravity="center"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:columnCount="2"
                android:useDefaultMargins="true">

                <LinearLayout
                    android:layout_margin="10dp"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="vertical">
                    <com.google.android.material.imageview.ShapeableImageView
                        android:id="@+id/vibrant_image_view"
                        android:layout_marginTop="10dp"
                        tools:ignore="InefficientWeight"
                        android:layout_width="100dp"
                        android:layout_height="100dp"
                        android:layout_weight="1"
                        android:adjustViewBounds="true"
                        android:scaleType="fitXY"
                        app:elevation="5dp"
                        app:shapeAppearance="@style/ShapeAppearanceColorPallate"
                        app:strokeColor="@color/colorPaletteBorder"
                        app:strokeWidth="1dp" />

                    <TextView
                        android:layout_marginTop="5dp"
                        android:gravity="center"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:textColor="@android:color/black"
                        android:text="@string/vibrant_color_label"
                        />

                    <!--<TextView
                        android:id="@+id/color_vibrant"
                        android:layout_marginTop="5dp"
                        android:gravity="center"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:textColor="@android:color/darker_gray"
                        android:text="#000000"
                        />
-->
                </LinearLayout>
                <LinearLayout
                    android:layout_margin="10dp"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="vertical">
                    <com.google.android.material.imageview.ShapeableImageView
                        android:id="@+id/light_vibrant_image_view"
                        android:layout_marginTop="10dp"
                        tools:ignore="InefficientWeight"
                        android:layout_width="100dp"
                        android:layout_height="100dp"
                        android:layout_weight="1"
                        android:adjustViewBounds="true"
                        android:scaleType="fitXY"
                        app:elevation="5dp"
                        app:shapeAppearance="@style/ShapeAppearanceColorPallate"
                        app:strokeColor="@color/colorPaletteBorder"
                        app:strokeWidth="1dp" />

                    <TextView
                        android:layout_marginTop="5dp"
                        android:gravity="center"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:textColor="@android:color/black"
                        android:text="@string/light_vibrant_color_label"
                        />
                </LinearLayout>
                <LinearLayout
                    android:layout_margin="10dp"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="vertical">
                    <com.google.android.material.imageview.ShapeableImageView
                        android:id="@+id/dark_vibrant_image_view"
                        android:layout_marginTop="10dp"
                        tools:ignore="InefficientWeight"
                        android:layout_width="100dp"
                        android:layout_height="100dp"
                        android:layout_weight="1"
                        android:adjustViewBounds="true"
                        android:scaleType="fitXY"
                        app:elevation="5dp"
                        app:shapeAppearance="@style/ShapeAppearanceColorPallate"
                        app:strokeColor="@color/colorPaletteBorder"
                        app:strokeWidth="1dp" />

                    <TextView
                        android:layout_marginTop="5dp"
                        android:gravity="center"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:textColor="@android:color/black"
                        android:text="@string/dark_vibrant_color_label"
                        />
                </LinearLayout>
                <LinearLayout
                    android:layout_margin="10dp"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="vertical">
                    <com.google.android.material.imageview.ShapeableImageView
                        android:id="@+id/muted_image_view"
                        android:layout_marginTop="10dp"
                        tools:ignore="InefficientWeight"
                        android:layout_width="100dp"
                        android:layout_height="100dp"
                        android:layout_weight="1"
                        android:adjustViewBounds="true"
                        android:scaleType="fitXY"
                        app:elevation="5dp"
                        app:shapeAppearance="@style/ShapeAppearanceColorPallate"
                        app:strokeColor="@color/colorPaletteBorder"
                        app:strokeWidth="1dp" />

                    <TextView
                        android:layout_marginTop="5dp"
                        android:gravity="center"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:textColor="@android:color/black"
                        android:text="@string/muted_color_label"
                        />
                </LinearLayout>
                <LinearLayout
                    android:layout_margin="10dp"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="vertical">
                    <com.google.android.material.imageview.ShapeableImageView
                        android:id="@+id/light_muted_image_view"
                        android:layout_marginTop="10dp"
                        tools:ignore="InefficientWeight"
                        android:layout_width="100dp"
                        android:layout_height="100dp"
                        android:layout_weight="1"
                        android:adjustViewBounds="true"
                        android:scaleType="fitXY"
                        app:elevation="5dp"
                        app:shapeAppearance="@style/ShapeAppearanceColorPallate"
                        app:strokeColor="@color/colorPaletteBorder"
                        app:strokeWidth="1dp" />

                    <TextView
                        android:layout_marginTop="5dp"
                        android:gravity="center"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:textColor="@android:color/black"
                        android:text="@string/light_muted_color_label"
                        />
                </LinearLayout>
                <LinearLayout
                    android:layout_margin="10dp"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="vertical">
                    <com.google.android.material.imageview.ShapeableImageView
                        android:id="@+id/dark_muted_image_view"
                        android:layout_marginTop="10dp"
                        tools:ignore="InefficientWeight"
                        android:layout_width="100dp"
                        android:layout_height="100dp"
                        android:layout_weight="1"
                        android:adjustViewBounds="true"
                        android:scaleType="fitXY"
                        app:elevation="5dp"
                        app:shapeAppearance="@style/ShapeAppearanceColorPallate"
                        app:strokeColor="@color/colorPaletteBorder"
                        app:strokeWidth="1dp" />

                    <TextView
                        android:layout_marginTop="5dp"
                        android:gravity="center"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:textColor="@android:color/black"
                        android:text="@string/dark_muted_color_label"
                        />
                </LinearLayout>
            </GridLayout>

        </LinearLayout>
    </androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
..
Here is my SettingsFragment.kt file
package com.boltuix.colorpalette

import android.graphics.BitmapFactory
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import androidx.annotation.DrawableRes
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.palette.graphics.Palette
import com.boltuix.colorpalette.databinding.FragmentColorPaletteBinding
import com.google.android.material.imageview.ShapeableImageView


class ColorPaletteFragment : Fragment() {
    private var _binding: FragmentColorPaletteBinding? = null

    // This property is only valid between onCreateView and
    // onDestroyView.
    private val binding get() = _binding!!


    private val defaultColor: Int get() = ContextCompat.getColor(
        requireContext(),
        R.color.colorPrimary
    )


    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        _binding = FragmentColorPaletteBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        val bitmap = BitmapFactory.decodeResource(resources, R.drawable.sample2)
        val palette = PaletteUtils.createPaletteSync(bitmap)
        binding.colorExtractionTargetImageView.apply {
            setImageBitmap(bitmap)
        }
        setVibrantPalette(view, palette)
        setMutedPalette(view, palette)
    }

    private fun setMutedPalette(view: View, palette: Palette) {
        binding.mutedImageView.apply {
            val color = palette.getMutedColor(defaultColor)
            setBackgroundColor(color)

            val psVibrant: Palette.Swatch = palette.vibrantSwatch!!
            val color1: Int = psVibrant.rgb
            val population: Int = psVibrant.population
            val hsl: FloatArray = psVibrant.hsl
            val bodyTextColor: Int = psVibrant.bodyTextColor
            val titleTextColor: Int = psVibrant.titleTextColor

            Log.d("color1","psVibrant:"+psVibrant)
            Log.d("color1","color1:"+color1)
            Log.d("color1","population:"+population)
            Log.d("color1","hsl:"+hsl)
            Log.d("color1","bodyTextColor:"+bodyTextColor)
            Log.d("color1","titleTextColor:"+titleTextColor)

        }
        view.findViewById<ShapeableImageView>(R.id.light_muted_image_view).apply {
            val color = palette.getLightMutedColor(defaultColor)
            setBackgroundColor(color)
        }
        view.findViewById<ShapeableImageView>(R.id.dark_muted_image_view).apply {
            val color = palette.getDarkMutedColor(defaultColor)
            setBackgroundColor(color)
        }
    }

    private fun setVibrantPalette(view: View, palette: Palette) {
        view.findViewById<ShapeableImageView>(R.id.vibrant_image_view).apply {
            val color = palette.getVibrantColor(defaultColor)
            setBackgroundColor(color)
        }
        view.findViewById<ShapeableImageView>(R.id.light_vibrant_image_view).apply {
            val color = palette.getLightVibrantColor(defaultColor)
            setBackgroundColor(color)
        }
        view.findViewById<ShapeableImageView>(R.id.dark_vibrant_image_view).apply {
            val color = palette.getDarkVibrantColor(defaultColor)
            setBackgroundColor(color)
        }
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }
}
..
PaletteUtils.kt

//https://developer.android.com/develop/ui/views/graphics/palette-colors
object PaletteUtils {
    fun createPaletteSync(bitmap: Bitmap): Palette = Palette.from(bitmap).generate()
}
..

GET source code on Github:

Comments