VOOZH about

URL: https://www.geeksforgeeks.org/kotlin/android-jetpack-compose-theme-picker-palette/

⇱ Android Jetpack Compose - Theme Picker Palette - GeeksforGeeks


  • Courses
  • Tutorials
  • Interview Prep

Android Jetpack Compose - Theme Picker Palette

Last Updated : 23 Jul, 2025

Jetpack Compose is a new UI toolkit from Google used to create native Android UI. It speeds up and simplifies UI development using less code, Kotlin APIs, and powerful tools.

Prerequisites:

  1. Familiar with Kotlin and OOP Concepts as well 
  2. basic understanding of Jetpack Compose
  3. Android Studio Canary Version (Programme was developed in the latest version => Android Studio Giraffe | 2022.3.1 Canary 11)

A sample video is given below to get an idea about what we will do in this article.

Step-by-Step Implementation

Step 1: Create a new Android studio project

To create a new project in Android Studio using Jetpack Compose please refer to:- How to Create a New Project in Android Studio Canary Version with Jetpack Compose.

Step 2: Let’s first review the build.gradle(module level)

Now go to the module-level build.gradle file & check on dependencies. If any of the dependencies are missing add them from the below snippet. Remember to double-check this file that everything is included. If something is missing just add those blocks from the below snippets.

@Suppress("DSL_SCOPE_VIOLATION") // TODO: Remove once KTIJ-19369 is fixed
plugins {
 alias(libs.plugins.com.android.application)
 alias(libs.plugins.org.jetbrains.kotlin.android)
}

android {
 namespace = "com.example.jetpackthemepicker"
 compileSdk = 33

 defaultConfig {
 applicationId = "com.example.jetpackthemepicker"
 minSdk = 24
 targetSdk = 33
 versionCode = 1
 versionName = "1.0"

 testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
 vectorDrawables {
 useSupportLibrary = true
 }
 }

 buildTypes {
 release {
 isMinifyEnabled = false
 proguardFiles(
 getDefaultProguardFile("proguard-android-optimize.txt"),
 "proguard-rules.pro"
 )
 }
 }
 compileOptions {
 sourceCompatibility = JavaVersion.VERSION_1_8
 targetCompatibility = JavaVersion.VERSION_1_8
 }
 kotlinOptions {
 jvmTarget = "1.8"
 }
 buildFeatures {
 compose = true
 }
 composeOptions {
 kotlinCompilerExtensionVersion = "1.3.2"
 }
 packaging {
 resources {
 excludes += "/META-INF/{AL2.0,LGPL2.1}"
 }
 }
}

dependencies {

 constraints {
 implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.10") {
 because("kotlin-stdlib-jdk7 is now a part of kotlin-stdlib")
 }
 implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.10") {
 because("kotlin-stdlib-jdk8 is now a part of kotlin-stdlib")
 }
 }
 implementation(libs.core.ktx)
 implementation(libs.lifecycle.runtime.ktx)
 implementation(libs.activity.compose)
 implementation(platform(libs.compose.bom))
 implementation(libs.ui)
 implementation(libs.ui.graphics)
 implementation(libs.ui.tooling.preview)
 implementation(libs.material3)
 implementation("androidx.core:core-ktx:1.10.0")
 implementation("com.google.android.material:material:1.8.0")
 testImplementation(libs.junit)
 androidTestImplementation(libs.androidx.test.ext.junit)
 androidTestImplementation(libs.espresso.core)
 androidTestImplementation(platform(libs.compose.bom))
 androidTestImplementation(libs.ui.test.junit4)
 debugImplementation(libs.ui.tooling)
 debugImplementation(libs.ui.test.manifest)
}

Step 3: Now let's review the build.gradle(project level)

Remember to double-check this file that everything is included. If something is missing just add those blocks from the below snippets.

// Top-level build file where you can add configuration 
// options common to all sub-projects/modules.
plugins {
 alias(libs.plugins.com.android.application) apply false
 alias(libs.plugins.org.jetbrains.kotlin.android) apply false
}

Step 4: Now let's review the libs.versions.toml(Version Catalog) and settings.gradle.kts

These files are special files that were introduced in the latest update of the Android version i.e. Android Studio Giraffe | 2022.3.1 Canary 11. A description of what this file holds onto is given below :

  • "libs.versions.toml" is a version catalog file that contains a list of all the dependencies and their corresponding version numbers used in a project. This file is typically used in a Gradle-based project and helps manage the versioning of external libraries.
  • "settings.gradle.kts" is a Gradle settings file that specifies the configuration settings for a Gradle-based project. This file typically contains information about the project structure, such as the location of the source code, the build output directory, and any included modules or plugins. The ".kts" extension indicates that the file is written in Kotlin Script, a scripting language that can be used with Gradle to configure and build projects.

libs.versions.toml

[versions]
com-android-application = "8.1.0-alpha11"
org-jetbrains-kotlin-android = "1.7.20"
core-ktx = "1.9.0"
junit = "4.13.2"
androidx-test-ext-junit = "1.1.5"
espresso-core = "3.5.1"
lifecycle-runtime-ktx = "2.3.1"
activity-compose = "1.5.1"
compose-bom = "2022.10.00"

[libraries]
core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "core-ktx" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-test-ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "androidx-test-ext-junit" }
espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espresso-core" }
lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycle-runtime-ktx" }
activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activity-compose" }
compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" }
ui = { group = "androidx.compose.ui", name = "ui" }
ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }
ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
material3 = { group = "androidx.compose.material3", name = "material3" }

[plugins]
com-android-application = { id = "com.android.application", version.ref = "com-android-application" }
org-jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version = "1.7.20" }

[bundles]

settings.gradle.kts

pluginManagement {
 repositories {
 google()
 mavenCentral()
 gradlePluginPortal()
 }
}
dependencyResolutionManagement {
 repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
 repositories {
 google()
 mavenCentral()
 }
}

rootProject.name = "JetpackThemePicker"
include(":app")

Step 5: Adding more colors to colors.xml and adding themes.xml

Add some colors for the theme picker and use them in different customization of themes. Goto Android->res->values->colors.xml and add the following stub of code:

<?xml version="1.0" encoding="utf-8"?>
<resources>
 <color name="colorPrimaryDark">#EB495C</color>
 <color name="colorPrimary">#E16876</color>
 <color name="colorPrimaryVariant">#E4A8AF</color>

 <color name="purple_200">#FFBB86FC</color>
 <color name="purple_500">#FF6200EE</color>
 <color name="purple_700">#FF3700B3</color>
 <color name="teal_200">#FF03DAC5</color>
 <color name="teal_700">#FF018786</color>
 <color name="black">#FF000000</color>
 <color name="white">#FFFFFFFF</color>
 <color name="blue">#0984e3</color>
 <color name="fruit">#6c5ce7</color>
 <color name="pink">#EF5366</color>
 <color name="orange">#e17055</color>
 <color name="pink40">#64EF5366</color>
 <color name="pink50">#80EF5366</color>
</resources>

Now goto Android->res->values->themes.xml and add the following stub of code:

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools">

 <style name="Theme.JetpackThemePicker" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
 <!-- Primary brand color. -->
 <item name="colorPrimary">@color/colorPrimary</item>
 <item name="colorPrimaryVariant">@color/colorPrimaryDark</item>
 <item name="colorOnPrimary">@color/white</item>
 <!-- Secondary brand color. -->
 <item name="colorSecondary">@color/teal_200</item>
 <item name="colorSecondaryVariant">@color/teal_700</item>
 <item name="colorOnSecondary">@color/black</item>
 <!-- Status bar color. -->
 <item name="android:statusBarColor" >?attr/colorPrimaryVariant</item>
 <!-- Customize your theme here. -->
 </style>

 <style name="Theme.JetpackThemePicker.NoActionBar">
 <item name="windowActionBar">false</item>
 <item name="windowNoTitle">true</item>
 </style>

 <style name="Theme.JetpackThemePicker.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />

 <style name="Theme.JetpackThemePicker.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
</resources>

Step 6: Now let's define the UI flow and navigation flow for the screens

This is the MainActivity class, which extends ComponentActivity.

  • The onCreate() method is overridden to set the content of the activity using the Jetpack Compose UI.
  • Inside the setContent block, two variables are defined using the remember function, which is used for state management in Compose. 
    • The first variable, systemUiController, is an instance of the SystemUiController class, which is used to control the system UI (status bar and navigation bar) of the device. The second variable, appTheme, is a mutable state variable of type AppThemeState.
  • A BaseView composable is used to set the layout of the activity. 
    • It takes the appTheme and systemUiController variables as parameters and sets the content of the activity to MainScreen() composable.
  • The MainScreen() composable is defined as a Column composable with a TopAppBar and a LazyColumn
    • The TopAppBar has a title set to "Jetpack theme picker". 
    • The LazyColumn is used to display a list of components returned by the getComponents() function. 
    • We are using this setup mainly because if in the future you need to add more components to the app you can easily add it to the getComponent() without changing much of the code.
    • In the getComponent() function the Component has two parameters named as componentName and className
  • The ButtonComponent() composable is defined to create a button for each item in the list. It takes two parameters, buttonText, and className
    • The buttonText parameter is the text to be displayed on the button, and className is the activity class that should be launched when the button is clicked.
  • The getComponents() function returns a list of Component objects, which contain the name and class of each activity to be displayed in the list. In this case, it returns only one Component object for a ThemeActivity.

Step 7: Creating a model data class of the Component

Create a new package as a model and create a Kotlin dataclass file in it named Component. This Component data class will have two properties: componentName and className.

  • The componentName property is a String that stores the name of the component.
  • The className property is a Class<*> type that stores the class object of the component. Class<*> is a special Kotlin type that represents a class, regardless of its type parameters. It is a way of referring to the class without actually creating an instance of it.

Step 8: Create a class that can be used as a state variable for managing the theme of the app (AppThemeState)

Goto Android -> Java -> com -> example -> ui -> theme and create a data class file named as AppThemeState. This class will have two properties:

  1. darkTheme: a boolean variable that indicates whether the app is currently using a dark theme. The default value is false.
  2. palette: a ColorPalette enum variable that represents the color scheme of the app. The default value is ColorPalette.PINK.

The data keyword used before the class definition automatically generates some methods such as equals(), hashCode(), toString(), and copy() for the class based on the properties defined in it.

This class can be used as a state variable for managing the theme of the app in a Jetpack Compose UI. When the darkTheme or palette properties of this class change, the UI that is using this state variable will recompose itself with the new values.

Step 9: Define colors, shapes, and typography for the theme

We will define some colors, shapes, and typography for the theme palette to choose from. You can also tinker with the values according to your preferences. Goto Android=>app=>java=>com=>example=>packagename(Here jetpackthemepicker)=>ui=>Color.kt and paste this stub of code

Color.kt

Goto Android=>app=>java=>com=>example=>packagename(Here jetpackthemepicker)=>ui=>Shape.kt and paste this stub of code

Shape.kt

Goto Android=>app=>java=>com=>example=>packagename(Here jetpackthemepicker)=>ui=>Type.kt and paste this stub of code

Type.kt

Step 10: Let us create a class named "SystemUI.kt" that provides methods to change the color of the status and navigation bars

This is a SystemUiController class that provides methods to change the color of the status and navigation bars on an Android device. The SystemUiController class takes a Window object as its constructor parameter, which is used to set the status and navigation bar colors. The class has three methods:

  • setStatusBarColor takes a Color object as input and sets the color of the status bar. It also takes two optional Boolean parameters: darkIcons, which specifies whether the status bar icons should be dark or light, and transformColorForLightContent, which is a lambda that transforms the color if dark icons were requested but are not available.
  • setNavigationBarColor takes a Color object as input and sets the color of the navigation bar. It also takes two optional Boolean parameters: darkIcons, which specifies whether the navigation bar icons should be dark or light, and transformColorForLightContent, which is a lambda that transforms the color if dark icons were requested but are not available.
  • setSystemBarsColor takes a Color object as input and calls setStatusBarColor and setNavigationBarColor with the same color and optional parameters.

We also define a LocalSystemUiController object, which can be used as a Composable function to provide the SystemUiController to the composition. Additionally, we define two private Color values and a lambda that can be used to transform the color for light content.

Step 11: For a custom Compose theme let's declare several predefined color palettes for light and dark modes in themes.kt

Let's create a custom Compose theme with several predefined color palettes for light and dark modes. In this class, we will declare 10 predefined color palettes for both light and dark modes. The colors are defined using the Color class provided by Compose, and the palettes are created using the darkColorScheme() and lightColorScheme() functions.

The ColorPalette enum class is used to specify which color palette to use. The JetpackTheme() function is the main entry point of the theme and takes in two parameters: darkTheme and colorPalette. The darkTheme parameter specifies whether to use the dark or light mode of the theme based on the system's current mode. The colorPalette parameter specifies which color palette to use for the theme.

The content parameter is a composable function that represents the content of the screen or component that the theme is applied to. To apply this theme to a Composable function or a screen, you need to wrap the content with the JetpackTheme() function and pass the desired darkTheme and colorPalette parameters.

Step 12: Now let's define a new Activity class ThemeActivity which lets the users change the theme of the screen

  • The ThemeActivity class extends the ComponentActivity class which is a base class for activities that use the modern Android view system, Jetpack Compose. It has a lateinit var property called appTheme which is a mutable state variable of the AppThemeState class. 
    • AppThemeState represents the current state of the theme, which includes a boolean flag to indicate whether the theme has been changed and a ColorPalette object to represent the selected color palette.
  • The onCreate function is called when the activity is created. It sets the content view of the activity using the setContent function which takes a composable function as an argument. 
    • In this case, the composable function is ThemeSample() which is defined later in the code. The remember function is used to create an instance of SystemUiController which is used to modify the system UI of the device, and an instance of MutableState for the appTheme variable.
  • The ThemeSample composable function is used to define the UI layout for ThemeActivity. It contains a Column layout, which has a TopAppBar at the top, and another Column layout below it. The second Column layout contains a Text view and a LazyVerticalGrid view.
  • The Column composable is used to create a vertical layout for the UI components in the screen. It has a Modifier that sets the background color of the column to MaterialTheme.colorScheme.background and makes it fill the maximum height of the screen. 
    • Inside the Column, there is a TopAppBar composable that displays a top app bar at the top of the screen. The title parameter is set to a Text composable that displays the text "Theme". The colors parameter sets the colors of the app bar. The containerColor is set to MaterialTheme.colorScheme.surfaceTint which is a color that represents the surface of the app. Finally, there is a navigationIcon parameter that sets the icon to an arrow back icon.
  • The TopAppBar contains the title of the screen, a navigation icon, and a background color. The navigationIcon is an IconButton with an arrow back icon that takes the user back to the previous screen when clicked.
  • The Text view displays the label "Change theme of this screen: " in the center and a medium headline font with a surface tint color.
  • The LazyVerticalGrid view is used to display the available color palettes in a grid layout. Each item in the grid is defined by the items parameter, which takes the size of the colorPallete array and an itemContent lambda function that defines the layout of each item.
  • Each item in the colorPallete array is rendered as a Box composable with a size of 100.dp, a rounded corner shape of 10.dp, and a background color defined by the getMaterialColor() extension function. 
    • When an item is clicked, its color palette is set as the new app theme. If the item's color palette is currently selected as the app theme, a checkmark icon is displayed in the center of the box. If not, then the box is not modified.
  • Finally, the ThemeSample composable function is annotated with the @OptIn annotation to enable experimental APIs used in the function, namely ExperimentalFoundationApi and ExperimentalMaterial3Api. The function is also annotated with the @Preview annotation to enable previewing the UI layout in Android Studio.

Step 13: Now let's register this new ThemeActivity as an activity in AndroidManifest.xml

Output:

Comment
Article Tags:

Explore