m.reiter
m.reiter

Reputation: 2545

How to retain tonal colours when adding additional content to a Material3 TopAppBar

I am developing an Android App using Jetpack Compose and Material3.

I have a screen consisting of a TopAppBar and a LazyColumn as content, linked together via scrollBehavior to achieve that nice material tonal elevation change:

enter image description here


I now want to add a filter-layout, which should look & feel like it's part of the top app bar


My simple implementation did not do the trick: the filter has no tonal elevation:

enter image description here

@Composable
fun TestScreen() {
    val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()

    Scaffold(
        topBar = {
            Column {
                TopAppBar(
                    title = { Text("Material3 top app bar") },
                    scrollBehavior = scrollBehavior,
                )
                Text(
                    text = "Filter - Filter - Filter - Filter - Filter",
                    modifier = Modifier
                        .fillMaxWidth()
                        .height(30.dp)
                )
                Divider()
            }
        },
        modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection)
    ) { contentPadding ->

        LazyColumn(Modifier.padding(contentPadding)) {
            items(100) { index ->
                Text(
                    text = "item $index",
                    modifier = Modifier.fillMaxWidth()
                )
            }
        }
    }
}

So how do i do this correctly? Sadly, unlike Material2, there is no "empty" TopAppBar i could find.

Upvotes: 0

Views: 237

Answers (2)

m.reiter
m.reiter

Reputation: 2545

Amiir Kalantari provided a beautiful answer :)

This answer builds on his code, making it reusable and including the correct imports. All praise goes to him for figuring out the hard part!

import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.FastOutLinearInEasing
import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.spring
import androidx.compose.foundation.background
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.material3.surfaceColorAtElevation
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.graphics.lerp
import androidx.compose.ui.unit.dp

// modelled after https://stackoverflow.com/a/76475561/12871582
public fun Modifier.topAppBarBackground(
    scrollBehavior: TopAppBarScrollBehavior,
): Modifier = composed {
    val colorTransitionFraction = scrollBehavior.state.overlappedFraction
    val fraction = if (colorTransitionFraction > 0.01f) 1f else 0f
    val appBarContainerColor by animateColorAsState(
        targetValue = lerp(
            MaterialTheme.colorScheme.surface,
            MaterialTheme.colorScheme.surfaceColorAtElevation(3.dp),
            FastOutLinearInEasing.transform(fraction)
        ),
        animationSpec = spring(stiffness = Spring.StiffnessMediumLow), label = ""
    )

    background(appBarContainerColor)
}

Upvotes: 0

Amiir Kalantari
Amiir Kalantari

Reputation: 126

hello you can use this code for customize your toolbar :

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TestScreen() {
    val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
    Scaffold(
    topBar = {
        Column {
            TopAppBar(
                title = { Text("Material3 top app bar") },
                scrollBehavior = scrollBehavior,
            )
            val colorTransitionFraction = scrollBehavior.state.overlappedFraction
            val fraction = if (colorTransitionFraction > 0.01f) 1f else 0f
            val appBarContainerColor by animateColorAsState(
                targetValue = lerp(
                    MaterialTheme.colorScheme.surface,
                    MaterialTheme.colorScheme.surfaceColorAtElevation(3.dp),
                    FastOutLinearInEasing.transform(fraction)
                ),
                animationSpec = spring(stiffness = Spring.StiffnessMediumLow), label = ""
            )
            Text(
                text = "Filter - Filter - Filter - Filter - Filter",
                modifier = Modifier
                    .fillMaxWidth()
                    .height(30.dp)
                    .background(appBarContainerColor)
            )
        }
    },
    modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection)
    ) { contentPadding ->
        LazyColumn(Modifier.padding(contentPadding)) {
            items(100) { index ->
                Text(
                    text = "item $index",
                    modifier = Modifier.fillMaxWidth()
                )
            }
       }
    }
}

Upvotes: 1

Related Questions