AnimatedTopAppBar: New custom content option, to also change scrollable color for content below.

This commit is contained in:
acclorite 2024-08-04 18:53:28 +03:00
parent 3d8e0b5f54
commit b1ebe72cc3
3 changed files with 93 additions and 84 deletions

View file

@ -1,16 +1,17 @@
package ua.acclorite.book_story.presentation.components
import androidx.compose.animation.core.FastOutLinearInEasing
import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.spring
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.statusBars
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
@ -18,12 +19,11 @@ import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.lerp
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.dp
import androidx.compose.ui.res.stringResource
import ua.acclorite.book_story.R
/**
* Animated top app bar.
@ -36,6 +36,7 @@ import androidx.compose.ui.unit.dp
* @param content1Visibility Whether first top app bar should be shown.
* @param content2Visibility Whether second top app bar should be shown.
* @param content3Visibility Whether third top app bar should be shown.
* @param customContent Custom content below [TopAppBar].
*/
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@ -59,98 +60,93 @@ fun AnimatedTopAppBar(
content3Visibility: Boolean? = null,
content3NavigationIcon: @Composable () -> Unit = {},
content3Title: @Composable () -> Unit = {},
content3Actions: @Composable RowScope.() -> Unit = {}
content3Actions: @Composable RowScope.() -> Unit = {},
customContent: @Composable ColumnScope.() -> Unit = {}
) {
Box(modifier = Modifier.fillMaxWidth()) {
val density = LocalDensity.current
val statusBarPadding = with(density) {
WindowInsets.statusBars.getTop(density).toDp()
}
val animatedContainerColor = lerp(
containerColor,
scrolledContainerColor,
animateFloatAsState(
if (isTopBarScrolled == true) 1f else 0f,
animationSpec = spring(
stiffness = Spring.StiffnessMediumLow
),
label = stringResource(id = R.string.top_app_bar_anim_content_desc)
).value
)
if (containerColor.alpha != 0f) {
Box(
modifier = Modifier
.fillMaxWidth()
.height(64.dp + statusBarPadding)
.background(
if (isTopBarScrolled == true) scrolledContainerColor
else containerColor
)
)
}
val animatedContainerColor = remember(
containerColor,
scrolledContainerColor,
isTopBarScrolled
) {
lerp(
containerColor,
scrolledContainerColor,
FastOutLinearInEasing.transform(if (isTopBarScrolled == true) 1f else 0f)
)
}
CustomAnimatedVisibility(
visible = content1Visibility ?: true,
enter = fadeIn(spring(stiffness = Spring.StiffnessMediumLow)),
exit = fadeOut(spring(stiffness = Spring.StiffnessMediumLow))
) {
TopAppBar(
windowInsets = WindowInsets.statusBars,
navigationIcon = content1NavigationIcon,
title = content1Title,
actions = content1Actions,
scrollBehavior = scrollBehavior,
modifier = Modifier.fillMaxWidth(),
colors = TopAppBarDefaults.topAppBarColors(
containerColor = animatedContainerColor,
scrolledContainerColor = scrolledContainerColor
)
)
}
if (content2Visibility != null) {
Column(
Modifier
.fillMaxWidth()
.background(animatedContainerColor)
) {
Box(modifier = Modifier.fillMaxWidth()) {
CustomAnimatedVisibility(
visible = content2Visibility,
visible = content1Visibility ?: true,
enter = fadeIn(spring(stiffness = Spring.StiffnessMediumLow)),
exit = fadeOut(spring(stiffness = Spring.StiffnessMediumLow))
) {
TopAppBar(
windowInsets = WindowInsets.statusBars,
navigationIcon = content2NavigationIcon,
title = content2Title,
actions = content2Actions,
navigationIcon = content1NavigationIcon,
title = content1Title,
actions = content1Actions,
scrollBehavior = scrollBehavior,
modifier = Modifier.fillMaxWidth(),
colors = TopAppBarDefaults.topAppBarColors(
containerColor = animatedContainerColor,
containerColor = if (isTopBarScrolled != null) Color.Transparent
else containerColor,
scrolledContainerColor = scrolledContainerColor
)
)
}
}
if (content3Visibility != null) {
CustomAnimatedVisibility(
visible = content3Visibility,
enter = fadeIn(spring(stiffness = Spring.StiffnessMediumLow)),
exit = fadeOut(spring(stiffness = Spring.StiffnessMediumLow))
) {
TopAppBar(
windowInsets = WindowInsets.statusBars,
navigationIcon = content3NavigationIcon,
title = content3Title,
actions = content3Actions,
scrollBehavior = scrollBehavior,
modifier = Modifier.fillMaxWidth(),
colors = TopAppBarDefaults.topAppBarColors(
containerColor = animatedContainerColor,
scrolledContainerColor = scrolledContainerColor
if (content2Visibility != null) {
CustomAnimatedVisibility(
visible = content2Visibility,
enter = fadeIn(spring(stiffness = Spring.StiffnessMediumLow)),
exit = fadeOut(spring(stiffness = Spring.StiffnessMediumLow))
) {
TopAppBar(
windowInsets = WindowInsets.statusBars,
navigationIcon = content2NavigationIcon,
title = content2Title,
actions = content2Actions,
scrollBehavior = scrollBehavior,
modifier = Modifier.fillMaxWidth(),
colors = TopAppBarDefaults.topAppBarColors(
containerColor = if (isTopBarScrolled != null) Color.Transparent
else containerColor,
scrolledContainerColor = scrolledContainerColor
)
)
)
}
}
if (content3Visibility != null) {
CustomAnimatedVisibility(
visible = content3Visibility,
enter = fadeIn(spring(stiffness = Spring.StiffnessMediumLow)),
exit = fadeOut(spring(stiffness = Spring.StiffnessMediumLow))
) {
TopAppBar(
windowInsets = WindowInsets.statusBars,
navigationIcon = content3NavigationIcon,
title = content3Title,
actions = content3Actions,
scrollBehavior = scrollBehavior,
modifier = Modifier.fillMaxWidth(),
colors = TopAppBarDefaults.topAppBarColors(
containerColor = if (isTopBarScrolled != null) Color.Transparent
else containerColor,
scrolledContainerColor = scrolledContainerColor
)
)
}
}
}
customContent()
}
}

View file

@ -33,12 +33,14 @@ import ua.acclorite.book_story.presentation.screens.library.data.LibraryEvent
* Tab row, either scrollable or static, depends on screen width.
*
* @param onEvent Event used to Scroll to Page.
* @param itemCountBackgroundColor Item count background color.
* @param books The list of all books.
* @param pagerState [PagerState].
*/
@Composable
fun LibraryTabRow(
onEvent: (LibraryEvent) -> Unit,
itemCountBackgroundColor: Color,
books: List<CategorizedBooks>,
pagerState: PagerState
) {
@ -113,7 +115,7 @@ fun LibraryTabRow(
text = tabItem.second.toString(),
modifier = Modifier
.background(
MaterialTheme.colorScheme.surfaceContainer,
itemCountBackgroundColor,
MaterialTheme.shapes.medium
)
.padding(horizontal = 8.dp, vertical = 4.dp),

View file

@ -1,5 +1,8 @@
package ua.acclorite.book_story.presentation.screens.library.components
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.spring
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
@ -168,12 +171,20 @@ fun LibraryTopBar(
},
content3Actions = {
MoreDropDown()
},
customContent = {
LibraryTabRow(
onEvent = onEvent,
books = state.value.categorizedBooks,
itemCountBackgroundColor = animateColorAsState(
if (state.value.hasSelectedItems) MaterialTheme.colorScheme.surfaceContainerHighest
else MaterialTheme.colorScheme.surfaceContainer,
animationSpec = spring(stiffness = Spring.StiffnessMediumLow),
label = stringResource(id = R.string.top_app_bar_anim_content_desc)
).value,
pagerState = pagerState
)
}
)
LibraryTabRow(
onEvent = onEvent,
books = state.value.categorizedBooks,
pagerState = pagerState
)
}
}