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 package ua.acclorite.book_story.presentation.components
import androidx.compose.animation.core.FastOutLinearInEasing
import androidx.compose.animation.core.Spring import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.spring import androidx.compose.animation.core.spring
import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut import androidx.compose.animation.fadeOut
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box 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.RowScope
import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.statusBars import androidx.compose.foundation.layout.statusBars
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
@ -18,12 +19,11 @@ import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.lerp import androidx.compose.ui.graphics.lerp
import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import ua.acclorite.book_story.R
/** /**
* Animated top app bar. * 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 content1Visibility Whether first top app bar should be shown.
* @param content2Visibility Whether second 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 content3Visibility Whether third top app bar should be shown.
* @param customContent Custom content below [TopAppBar].
*/ */
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
@ -59,38 +60,28 @@ fun AnimatedTopAppBar(
content3Visibility: Boolean? = null, content3Visibility: Boolean? = null,
content3NavigationIcon: @Composable () -> Unit = {}, content3NavigationIcon: @Composable () -> Unit = {},
content3Title: @Composable () -> Unit = {}, content3Title: @Composable () -> Unit = {},
content3Actions: @Composable RowScope.() -> Unit = {} content3Actions: @Composable RowScope.() -> Unit = {},
customContent: @Composable ColumnScope.() -> Unit = {}
) { ) {
Box(modifier = Modifier.fillMaxWidth()) { val animatedContainerColor = lerp(
val density = LocalDensity.current containerColor,
val statusBarPadding = with(density) { scrolledContainerColor,
WindowInsets.statusBars.getTop(density).toDp() 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) { Column(
Box( Modifier
modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.height(64.dp + statusBarPadding) .background(animatedContainerColor)
.background(
if (isTopBarScrolled == true) scrolledContainerColor
else containerColor
)
)
}
val animatedContainerColor = remember(
containerColor,
scrolledContainerColor,
isTopBarScrolled
) { ) {
lerp( Box(modifier = Modifier.fillMaxWidth()) {
containerColor,
scrolledContainerColor,
FastOutLinearInEasing.transform(if (isTopBarScrolled == true) 1f else 0f)
)
}
CustomAnimatedVisibility( CustomAnimatedVisibility(
visible = content1Visibility ?: true, visible = content1Visibility ?: true,
enter = fadeIn(spring(stiffness = Spring.StiffnessMediumLow)), enter = fadeIn(spring(stiffness = Spring.StiffnessMediumLow)),
@ -104,7 +95,8 @@ fun AnimatedTopAppBar(
scrollBehavior = scrollBehavior, scrollBehavior = scrollBehavior,
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
colors = TopAppBarDefaults.topAppBarColors( colors = TopAppBarDefaults.topAppBarColors(
containerColor = animatedContainerColor, containerColor = if (isTopBarScrolled != null) Color.Transparent
else containerColor,
scrolledContainerColor = scrolledContainerColor scrolledContainerColor = scrolledContainerColor
) )
) )
@ -124,7 +116,8 @@ fun AnimatedTopAppBar(
scrollBehavior = scrollBehavior, scrollBehavior = scrollBehavior,
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
colors = TopAppBarDefaults.topAppBarColors( colors = TopAppBarDefaults.topAppBarColors(
containerColor = animatedContainerColor, containerColor = if (isTopBarScrolled != null) Color.Transparent
else containerColor,
scrolledContainerColor = scrolledContainerColor scrolledContainerColor = scrolledContainerColor
) )
) )
@ -145,13 +138,16 @@ fun AnimatedTopAppBar(
scrollBehavior = scrollBehavior, scrollBehavior = scrollBehavior,
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
colors = TopAppBarDefaults.topAppBarColors( colors = TopAppBarDefaults.topAppBarColors(
containerColor = animatedContainerColor, containerColor = if (isTopBarScrolled != null) Color.Transparent
else containerColor,
scrolledContainerColor = scrolledContainerColor 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. * Tab row, either scrollable or static, depends on screen width.
* *
* @param onEvent Event used to Scroll to Page. * @param onEvent Event used to Scroll to Page.
* @param itemCountBackgroundColor Item count background color.
* @param books The list of all books. * @param books The list of all books.
* @param pagerState [PagerState]. * @param pagerState [PagerState].
*/ */
@Composable @Composable
fun LibraryTabRow( fun LibraryTabRow(
onEvent: (LibraryEvent) -> Unit, onEvent: (LibraryEvent) -> Unit,
itemCountBackgroundColor: Color,
books: List<CategorizedBooks>, books: List<CategorizedBooks>,
pagerState: PagerState pagerState: PagerState
) { ) {
@ -113,7 +115,7 @@ fun LibraryTabRow(
text = tabItem.second.toString(), text = tabItem.second.toString(),
modifier = Modifier modifier = Modifier
.background( .background(
MaterialTheme.colorScheme.surfaceContainer, itemCountBackgroundColor,
MaterialTheme.shapes.medium MaterialTheme.shapes.medium
) )
.padding(horizontal = 8.dp, vertical = 4.dp), .padding(horizontal = 8.dp, vertical = 4.dp),

View file

@ -1,5 +1,8 @@
package ua.acclorite.book_story.presentation.screens.library.components 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.background
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
@ -168,12 +171,20 @@ fun LibraryTopBar(
}, },
content3Actions = { content3Actions = {
MoreDropDown() MoreDropDown()
} },
) customContent = {
LibraryTabRow( LibraryTabRow(
onEvent = onEvent, onEvent = onEvent,
books = state.value.categorizedBooks, 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 pagerState = pagerState
) )
} }
)
}
} }