Hello in my project id like to create a pager that slides to show the user some informations before being able to go throught the app. A bit like an onboarding. the issue is that i discovered while coding that the part 5 the buttons is always the same in evry pages so i want to code it only once on the pager. Any ideas on how to do that ? code of the pager:
@Composable
fun TTPOAOnboardingView(
onSkip: () -> Unit,
onContinue: () -> Unit,
) {
var selectedIndex by remember { mutableIntStateOf(1) }
val tabs = 5
val pagerState = rememberPagerState(
initialPage = 0, pageCount = { 5 })
val listState = rememberLazyListState()
LaunchedEffect(selectedIndex) {
pagerState.animateScrollToPage(selectedIndex)
listState.animateScrollToItem(selectedIndex)
}
LaunchedEffect(pagerState.currentPage) {
selectedIndex = pagerState.currentPage
listState.animateScrollToItem(pagerState.currentPage)
}
Box(
Modifier.fillMaxSize()
) {
Image(
painter = painterResource(R.drawable.ttpoa_onboarding_bg),
contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier.fillMaxSize()
)
Column(
modifier = Modifier.fillMaxSize(),
) {
LazyRow(
state = listState,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 6.dp, vertical = 8.dp)
.background(Color.Transparent),
horizontalArrangement = Arrangement.spacedBy(1.dp)
) {
items(tabs) { index ->
val backgroundColor =
if (index <= selectedIndex) StancerColor.TextBlue.color else StancerColor.TextRed.color
Box(
modifier = Modifier
.background(backgroundColor)
.padding(horizontal = 10.dp),
contentAlignment = Alignment.Center
) {
Box(
Modifier
.height(3.dp)
.width(70.dp)
.background(backgroundColor)
)
}
}
}
HorizontalPager(
state = pagerState, modifier = Modifier.weight(1f)
) { pageIndex ->
when (pageIndex) {
0 -> {
TTPOAOnboardingFirstScreen(
onSkip = {}) { }
}
1 -> {
TTPOAOnboardingSecondScreen(
onSkip = { /*TODO()*/ },
onContinue = { /*TODO()*/ })
}
2 -> {
TTPOAOnboardingThirdScreen(
onSkip = { /*TODO()*/ },
onContinue = { /*TODO()*/ })
}
3 -> {
}
4 -> {
}
}
}
}
}
here is the code of one of my pages:
@Composable
fun TTPOAOnboardingThirdScreen(
onSkip: () -> Unit,
onContinue: () -> Unit,
) {
Box(modifier = Modifier.fillMaxSize()) {
/* ---------- 2) MOCK-UP TELEPHONE ---------- */
Image(
painter = painterResource(R.drawable.ttpoa_tap_android),
contentDescription = "Démonstration Tap to Pay",
modifier = Modifier
.align(Alignment.BottomCenter)
.aspectRatio(0.30f).padding(top = 130.dp)
)
/* ---------- 3) VOILE BLANC DÉGRADÉ ---------- */
Box(
modifier = Modifier
.fillMaxWidth()
.height(250.dp) // ajuste la hauteur du fondu
.align(Alignment.BottomCenter)
.background(
brush = Brush.verticalGradient(
colors = listOf(
Color.Transparent,
Color.White,
Color.White
)
)
)
)
/* ---------- 4) CONTENU (TITRE) ---------- */
Column(
modifier = Modifier
.fillMaxSize()
.padding(horizontal = 24.dp, vertical = 32.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = "Choisissez Tap to Pay et présente votre Android au client",
style = Title1,
textAlign = TextAlign.Center,
modifier = Modifier.padding(top = 40.dp)
)
/* ---------- 5) CONTENU (Buttons) ---------- */
Spacer(Modifier.weight(1f))
Row(
modifier = Modifier
.fillMaxWidth()
.height(56.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
TextButton(onClick = onSkip) {
Text("Passer", style = Callout, color = StancerColor.Grey900.color)
}
StancerButton(
title = "Continuer",
modifier = Modifier.width(150.dp),
isLoading = false,
isEnabled = true,
backgroundColor = StancerColor.TextBlue
) { onContinue() }
}
}}
You can move the Button
s outside of the HorizontalPager
:
@Preview
@Composable
fun HorizontalPagerDemo(
onSkip: () -> Unit = {}, // skip introduction
onContinue: () -> Unit = {} // continue after introduction is finished
) {
val coroutineScope = rememberCoroutineScope()
val pagerState = rememberPagerState { 5 }
Column(
modifier = Modifier
.safeContentPadding()
.fillMaxSize(),
) {
// LazyRow...
HorizontalPager(
modifier = Modifier.weight(1f),
state = pagerState
) { pageIndex ->
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text(
text = "Page $pageIndex",
fontSize = 25.sp
)
}
}
Row(
modifier = Modifier.fillMaxWidth()
) {
Button(
modifier = Modifier.weight(1f),
onClick = onSkip
) {
Text("PASSER")
}
Spacer(modifier = Modifier.size(8.dp))
Button(
modifier = Modifier.weight(1f),
onClick = {
if (pagerState.currentPage < pagerState.pageCount - 1) {
// navigate to next page
coroutineScope.launch {
pagerState.animateScrollToPage(pagerState.currentPage + 1)
}
} else {
// navigate to next screen
onContinue()
}
}
) {
Text("CONTINUER")
}
}
}
}
Alternatively, if you want the Button
s to really be in front of the content, you can use a Box
Composable with the following structure:
Box {
Column(
modifier = Modifier.fillMaxSize()
) {
LazyRow()
HorizontalPager()
}
Row(
modifier = Modifier.align(Alignment.BottomCenter)
) {
Button()
Button()
}
}
Output: