Implementing onBoarding ViewPager Using JetPack Compose

Lets jump straight in to the example

Necessary implementation to the app level build gradle file

// Paging Compose
implementation "com.google.accompanist:accompanist-pager:0.13.0"
implementation "com.google.accompanist:accompanist-pager-indicators:0.13.0"

implementation "androidx.hilt:hilt-navigation-fragment:1.0.0"
implementation "androidx.hilt:hilt-navigation-compose:1.0.0-alpha03"
implementation "androidx.navigation:navigation-compose:2.4.0-alpha04"

implementation "androidx.compose.runtime:runtime-livedata:$compose_version"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1"

First we will be creating a data class which holds a data for on boarding screen

data class SampleOnBoard(
val image: Int,
val title: String,
val desc: String
)

So i am passing value to data class SampleOnBoard

val onBoardItem = listOf(
SampleOnBoard(
R.drawable.onboard1,
"Make it Easy One",
"Lorem Ipsum is simply dummy text of the printing and typesetting Industry."
),
SampleOnBoard(
R.drawable.onboard2,
"Make it Easy Two",
"Lorem Ipsum is simply dummy text of the printing and typesetting Industry."
),
SampleOnBoard(
R.drawable.onboard3,
"Make it Easy Three",
"Lorem Ipsum is simply dummy text of the printing and typesetting Industry."
)
)

So final Page of SampleOnBoard class will be

data class SampleOnBoard(
val image: Int,
val title: String,
val desc: String
)

val onBoardItem = listOf(
SampleOnBoard(
R.drawable.onboard1,
"Make it Easy One",
"Lorem Ipsum is simply dummy text of the printing and typesetting Industry."
),
SampleOnBoard(
R.drawable.onboard2,
"Make it Easy Two",
"Lorem Ipsum is simply dummy text of the printing and typesetting Industry."
),
SampleOnBoard(
R.drawable.onboard3,
"Make it Easy Three",
"Lorem Ipsum is simply dummy text of the printing and typesetting Industry."
)
)

Next we will be creating a viewmodel class called OnBoardViewModel

class OnBoardViewModel : ViewModel() {
private val _currentPage = MutableStateFlow(0)
val currentPage: StateFlow<Int> get() = _currentPage

fun setCurrentPage(currentPage: Int) {
_currentPage.value = currentPage
}
}

we created a StateFlow for current page. The main use of StateFlow is its an interface which has read only property it always return the updated value which is implemented through MutableStateFlow if same value updated means it doesn't return the value.

Lets have a look in to MainActivity code, the use of line is marked with double slash on the program

@ExperimentalPagerApi
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

window.statusBarColor = ContextCompat.getColor(this, R.color.gray)

setContent {
OnBoardScreenTheme {
Surface(color = MaterialTheme.colors.background) {
OnBoardScreen()
}
}
}
}
}

@ExperimentalPagerApi
@Composable
fun OnBoardScreen() {
val scaffoldState = rememberScaffoldState()
val scope = rememberCoroutineScope()
val onBoardViewModel : OnBoardViewModel = viewModel()
val context = LocalContext.current
val currentPage = onBoardViewModel.currentPage.collectAsState()

Toast.makeText(context, "${currentPage.value}", Toast.LENGTH_SHORT).show()

val pagerState = rememberPagerState(
pageCount = onBoardItem.size,
initialOffscreenLimit = 2,
initialPage = 0,
infiniteLoop = false
)
//Scafffold - helps us to design UI by using Material Layout Design Structure it allocate slot for common top level material component like topappbar,Bottomappbar,Drawer and Floating action button.// Scaffold(
modifier = Modifier.fillMaxSize(),
scaffoldState = scaffoldState
) {
//Just make use of all material component
Surface(
modifier = Modifier.fillMaxSize()
) {
scope.launch {
//Moves the page to next view based on postion
pagerState.animateScrollToPage(
page = currentPage.value
)
}
//Similar to FrameLayout in android we can overlap view inside Box Box(
modifier = Modifier
.fillMaxWidth()
.background(Gray200)
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally
) {
HorizontalPager(
state = pagerState
) { page ->
Column(
modifier = Modifier
.padding(top = 65.dp)
.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
Image(
painter = painterResource(id = onBoardItem[page].image),
contentDescription = "OnBoardImage",
modifier = Modifier
.size(250.dp)
)

Text(
text = onBoardItem[page].title,
modifier = Modifier
.padding(top = 50.dp),
color = Color.White,
fontWeight = FontWeight.Bold,
fontSize = 20.sp
)

Text(
text = onBoardItem[page].desc,
modifier = Modifier
.padding(30.dp),
color = Color.White,
fontSize = 18.sp,
textAlign = TextAlign.Center
)
}
}


}

Box(
modifier = Modifier
.align(Alignment.BottomCenter)
) {
Row(
modifier = Modifier
.padding(bottom = 20.dp)
.fillMaxWidth(),
horizontalArrangement = if (pagerState.currentPage != 2 ) {
Arrangement.SpaceBetween
} else {
Arrangement.Center
}
) {
if (pagerState.currentPage == 2) {
OutlinedButton(
onClick = {
Toast.makeText(context, "Start the Screen", Toast.LENGTH_SHORT).show()
},
shape = RoundedCornerShape(45.dp)
) {
Text(
text = "Get Started",
modifier = Modifier.padding(
vertical = 8.dp,
horizontal = 40.dp
),
color = Color.Black
)
}
} else {
Text(
text = "Skip",
color = Color.White,
modifier = Modifier.padding(start = 20.dp),
fontSize = 18.sp,
fontWeight = FontWeight.Medium
)

Text(
text = "Next",
color = Color.White,
modifier = Modifier
.clickable {
onBoardViewModel.setCurrentPage(pagerState.currentPage + 1)
}
.padding(end = 20.dp),
fontSize = 18.sp,
fontWeight = FontWeight.Medium
)
}
}
}
}
}
}
}