I am using Voyager in my compose multiplatform project and I have a question regarding how we can show/hide the bottom tab bar based on the scrolling direction of a LazyColumn inside HomeTab. I have handled the Scroll listener to provide me the value (show/hide) but I am not sure how to set up listener within App screen and handle data between HomeTab and App.
Please go through my code and let me know if I have any other ways where I can setup or how I can handle this issue with following code. Thanks for any help.
@OptIn(ExperimentalMaterialApi::class)
@Composable
fun App() {
MoviesTheme {
TabNavigator(HomeTab) {
BottomSheetNavigator(
modifier = Modifier.animateContentSize(),
sheetShape = RoundedCornerShape(topStart = 32.dp, topEnd = 32.dp),
skipHalfExpanded = true
) {
Navigator(Application()) { navigator -> SlideTransition(navigator) }
}
}
}
}
class Application : Screen {
@Composable
override fun Content() {
Scaffold(
modifier = Modifier,
scaffoldState = rememberScaffoldState(),
bottomBar = {
NavigationBar(tonalElevation = 4.dp) {
TabNavigationItemM3(HomeTab)
TabNavigationItemM3(FavoritesTab)
TabNavigationItemM3(InterestsTab)
TabNavigationItemM3(ProfileTab)
}
},
) {
CurrentTab()
}
}
}
@Composable
private fun RowScope.TabNavigationItemM3(tab: Tab) {
val tabNavigator = LocalTabNavigator.current
NavigationBarItem(
selected = tabNavigator.current.key == tab.key,
onClick = { tabNavigator.current = tab },
icon = {
tab.options.icon?.let { painter ->
androidx.compose.material3.Icon(
painter = painter,
contentDescription = tab.options.title
)
}
}
)
}
object HomeTab : Tab {
@Composable
override fun Content() {
HomeScreen(onScrollDirectionChanged = {show -> }, onScrollStopped = {})
}
override val options: TabOptions
@Composable
get() {
val icon = rememberVectorPainter(Icons.Rounded.Home)
return remember { TabOptions(index = 0u, title = "Home", icon = icon) }
}
}
@Composable
fun HomeScreen(
screenModel: HomeScreenViewModel = koinInject(),
navigator: Navigator = LocalNavigator.currentOrThrow,
onScrollDirectionChanged: (Boolean) -> Unit,
onScrollStopped: () -> Unit = {}
) {
LaunchedEffect(Unit) { screenModel.onLaunch() }
val pagingItems =
screenModel.allMoviesPagingState.collectAsLazyPagingItemsForRecipe(screenModel::onLoadMore)
val trendingPagingItems =
screenModel.trendingMoviesPagingState.collectAsLazyPagingItemsForMovies(screenModel::onLoadMoreTrending)
val listState = rememberLazyListState()
val previousScrollOffset by rememberUpdatedState(listState.firstVisibleItemScrollOffset)
var isScrollingDown by remember { mutableStateOf(false) }
var isScrollingUp by remember { mutableStateOf(false) }
LaunchedEffect(listState) {
snapshotFlow { listState.isScrollInProgress }
.collect {
if (it) {
isScrollingDown = listState.firstVisibleItemScrollOffset > previousScrollOffset
isScrollingUp = listState.firstVisibleItemScrollOffset < previousScrollOffset
onScrollDirectionChanged(isScrollingUp)
} else {
onScrollStopped()
}
}
}
if (listState.firstVisibleItemIndex == listState.layoutInfo.totalItemsCount - 1) {
onScrollDirectionChanged(true)
}
Box {
LazyColumn(
state = listState,
horizontalAlignment = Alignment.Start,
verticalArrangement = Arrangement.Top
) {
trendingMovies(trendingPagingItems, { id -> navigator.push(DetailsScreen(id)) }, {})
allMovies(pagingItems, { id -> navigator.push(DetailsScreen(id)) }, {})
}
MoviesSearchBar { }
}
}
you can show:
and close:
you need to add this voyager library:
implementation("cafe.adriel.voyager:voyager-bottom-sheet-navigator:$voyagerVersion")