Exploring Jetpack Compose: Building a Feature Introduction Screen with HorizontalPager
In this article, we’ll explore how to use HorizontalPager
to create a captivating feature introduction screen in your Android app.
Setting the Stage with Dependencies
To get started, ensure you have the necessary dependencies in your build.gradle
file:
implementation("androidx.compose.ui:ui:$compose_version")
implementation("androidx.compose.foundation:foundation:$compose_version")
implementation("androidx.compose.material:material:$compose_version")
implementation("androidx.navigation:navigation-compose:$navigation_version")
Replace $compose_version
and $navigation_version
with the latest versions available.
The GreetingScreen Composable
Our main attraction is the GreetingScreen
composable, where the magic happens. This composable leverages HorizontalPager
to showcase different greetings to the user, guiding them through the app's features.
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun GreetingScreen(){
val greetings = listOf(
Triple(R.drawable.img_greeting_2,"All your favorites","Get all your loved foods in one once place, you just place the orer we do the rest"),
Triple(R.drawable.img_greeting_4,"All your favorites","Get all your loved foods in one once place, you just place the orer we do the rest"),
Triple(R.drawable.img_greeting_3,"Order from choosen chef","Get all your loved foods in one once place, you just place the orer we do the rest"),
Triple(R.drawable.img_greeting_1,"Free delivery offers","Get all your loved foods in one once place, you just place the orer we do the rest")
)
var buttonName by rememberSaveable { mutableStateOf("Next") }
var visibleSkip by remember { mutableStateOf(true) }
val pagerState = rememberPagerState{greetings.size}
val scope = rememberCoroutineScope()
LaunchedEffect(pagerState) {
snapshotFlow { pagerState.currentPage }.collect { page ->
if (page<3) {
visibleSkip = true
buttonName = "Next"
}else{
visibleSkip = false
buttonName = "Get Started"
}
}
}
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.fillMaxSize()
.padding(top = 24.dp, bottom = 16.dp)
) {
HorizontalPager(
modifier = Modifier.weight(1f),
state = pagerState,
key = {greetings[it]},
pageSize = PageSize.Fill
) {
ItemGreeting(greetings[it])
}
Spacer(modifier = Modifier.height(32.dp))
DotsIndicator(
totalDots = greetings.size,
selectedIndex = pagerState.currentPage,
selectedColor = R.color.orange,
unSelectedColor = R.color.orange_light
)
Spacer(modifier = Modifier.height(64.dp))
OrangeButton(
title = buttonName,
modifier = Modifier.padding(start = 24.dp, end = 24.dp)) {
if (pagerState.currentPage ==0 || pagerState.currentPage<3) {
scope.launch {
pagerState.animateScrollToPage(
pagerState.currentPage + 1
)
}
}else {
//start app
}
}
Spacer(modifier = Modifier.height(16.dp))
if(visibleSkip)
Text(text = "Skip",
modifier = Modifier
.height(48.dp)
.padding(horizontal = 12.dp, vertical = 12.dp)
.clickable {
navController?.navigate(Screen.LoginPhone.route) {
popUpTo(navController.graph.startDestinationId)
launchSingleTop = true
}
},
textAlign = TextAlign.Center,
fontFamily = FontFamily(Font(R.font.sen_regular)),
fontSize = 16.sp,
color = colorResource(id = R.color.blue_dark3)
)
else Spacer(modifier = Modifier.height(48.dp))
}
}
Diving into HorizontalPager
The heart of our feature introduction screen is the HorizontalPager
. This powerful composable allows us to display a series of greetings horizontally, providing an engaging user experience.
HorizontalPager(
modifier = Modifier.weight(1f),
state = pagerState,
key = {greetings[it]},
pageSize = PageSize.Fill
) {
ItemGreeting(greetings[it])
}
Each page in the pager is represented by the ItemGreeting
composable, which encapsulates the content and layout for individual greetings.
@Composable
fun ItemGreeting(item:Triple<Int,String,String>){
Column(
verticalArrangement = Arrangement.Center,
modifier = Modifier
.fillMaxHeight()
.padding(start = 24.dp, end = 24.dp),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Image(painter = painterResource(id = item.first),
contentDescription = "image",
contentScale = ContentScale.Crop,
modifier = Modifier
.height(300.dp)
.width(240.dp)
.clip(RoundedCornerShape(10.dp))
)
Spacer(modifier = Modifier.height(64.dp))
Text(
text = item.second,
fontFamily = FontFamily(Font(R.font.sen_extrabold)),
fontSize = 24.sp,
color = colorResource(id = R.color.blue_dark)
)
Spacer(modifier = Modifier.height(24.dp))
Text(
text = item.third,
fontFamily = FontFamily(Font(R.font.sen_regular)),
fontSize = 16.sp,
textAlign = TextAlign.Center,
color = colorResource(id = R.color.blue_dark3)
)
}
}
Adding Interactivity with Buttons and Indicators
Our feature introduction screen wouldn’t be complete without user interaction elements. We’ve included an OrangeButton
for navigation and a DotsIndicator
to visually represent the number of pages.
@Composable
fun OrangeButton(
title:String,
modifier: Modifier = Modifier,
onClick:()->Unit
){
Button(
modifier = modifier
.fillMaxWidth()
.height(56.dp),
shape = RoundedCornerShape(12),
colors = ButtonDefaults.textButtonColors(colorResource(id = R.color.orange)),
onClick = {
onClick()
}) {
Text(
text = title,
fontFamily = FontFamily(Font(R.font.sen_regular)),
fontSize = 16.sp,
color = colorResource(id = R.color.white)
)
}
}
@Composable
fun DotsIndicator(
totalDots : Int,
selectedIndex : Int,
selectedColor: Int,
unSelectedColor: Int,
){
LazyRow(
modifier = Modifier
.wrapContentWidth()
.wrapContentHeight()
) {
items(totalDots) { index ->
if (index == selectedIndex) {
Box(
modifier = Modifier
.size(10.dp)
.clip(CircleShape)
.background(colorResource(id = selectedColor))
)
} else {
Box(
modifier = Modifier
.size(10.dp)
.clip(CircleShape)
.background(colorResource(id = unSelectedColor))
)
}
if (index != totalDots - 1) {
Spacer(modifier = Modifier.padding(horizontal = 8.dp))
}
}
}
}
Conclusion
In this exploration of Jetpack Compose, we’ve crafted a feature introduction screen using HorizontalPager
to guide users through the app's key elements. Leveraging Compose's declarative syntax and powerful composables, we've created an engaging and visually appealing user experience.
Happy Composing!