androidkotlinmaterial-designandroid-jetpack-composematerial-design-3

How to not use a custom colour in a custom TopAppBar


During cetrain times I want to use my own color resource ColorGreen to change the background colour of my custom SmallTopAppBar, and during other times I don't want to use it so that the default black and white colours are used instead depending on the device's current theme. What is the best way to avoid a possible null pointer exception? Should an 'if null' statement be used in the custom toolbar code? Should null be used in the activity declaration where the underscores are?

Color.kt

val ColorGreen = Color(0,110,20,255)

Custom toolbar code

package com.mycompany.myapp.ui.components

import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.SmallTopAppBar
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.style.TextAlign

@Composable
fun MySmallTopAppBar(
    backgroundColor: Color,
    title: String,
    titleColor: Color
) {
    SmallTopAppBar(
        colors = TopAppBarDefaults.smallTopAppBarColors(
            containerColor = backgroundColor),
        title = {
            Text(
                text = title,
                style = MaterialTheme.typography.titleMedium,
                textAlign = TextAlign.Start,
                maxLines = 1,
                color = titleColor
            )
        }
    )
}

within MainActivity.kt

...
    setContent {

        MyAppTheme {
            Surface(
                modifier = Modifier.fillMaxSize(),
                color = MaterialTheme.colorScheme.background
            ) {
                Scaffold(
                    topBar = { MySmallTopAppBar(ColorGreen, getGreetingMessage(), __) }
                ) {
                }
            }
        }
    }
...

Solution

  • In such cases you need to inspect component source code to understand how it works.

    In case of Text, default color value is Color.Unspecified - if this value is used, color will be taken from the style or from LocalContentColor (of style value is unspecified too). So if you want to follow default behaviour, you need to pass this value it too:

    val backgroundColor: Color?
    // ...
    MySmallTopAppBar(backgroundColor, getGreetingMessage(), if (backgroundColor == null) Color.Unspecified else Color.SomeColor)
    

    In case if smallTopAppBarColors default value is internal, plus since it may change in the future(as material 3 is in alpha so far), the most correct way would be something like this:

    colors = if (backgroundColor != null)
        TopAppBarDefaults.smallTopAppBarColors(containerColor = backgroundColor)
    else
        TopAppBarDefaults.smallTopAppBarColors(),