22 April 2024

Writing app onboarding with version support.

Jetpack Compose code for an onboarding screen featuring asynchronous image loading, customizable title, subtitle, button, and pagination indicators. Utilizes modern UI components and layouts for a dynamic user experience.

This Jetpack Compose tutorial showcases a streamlined onboarding screen, crucial for engaging and guiding new users through an app’s features.

What is an onboarding screen?

Onboarding screens are introductory screens users encounter when launching an app for the first time, designed to familiarize them with the app’s features and functionalities. They aim to guide users through the initial setup, highlight key app benefits, and enhance user engagement, ultimately improving user retention and satisfaction.

Let’s start with the code

@Composable
fun OnboardingPage(onboarding: OnboardingModel.Screen?, onClick: () -> Unit, totalItems: Int, currentPos: Int) {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        // Rest of the below code snippets till page indicator will go here
    }
}

OnboardingPage Composable Function

This is a Composable function named OnboardingPage that takes four parameters:

Column Layout Modifiers

This creates a Column layout with the following modifiers:

AsyncImage(
    model = onboarding?.imageUrl,
    contentDescription = "App Screenshot",
    modifier = Modifier
        .height(500.dp)
        .fillMaxWidth(),
    contentScale = ContentScale.Fit
)

AsyncImage Composable

This is an AsyncImage composable that displays an image asynchronously:

Text(
    text = onboarding?.title.orEmpty(),
    fontSize = 19.sp,
    fontFamily = latoFamily,
    fontWeight = FontWeight.Bold,
    textAlign = TextAlign.Center,
    color = t1Inverse()
)

Displays the title of the onboarding screen using a Text composable with specified attributes including:

Text(
    text = onboarding?.subtitle.orEmpty(),
    fontSize = 15.sp,
    color = t2Inverse(),
    fontFamily = latoFamily,
    fontWeight = FontWeight.Normal,
    lineHeight = 18.sp,
    textAlign = TextAlign.Center,
)

Displays the subtitle of the onboarding screen using another Text composable with similar attributes.

NextButton(
    title = onboarding?.buttonTitle.orEmpty(),
    onClick = onClick,
    isEnabled = onboarding?.buttonEnable == true
)

This calls the NextButton composable passing the following parameters:

Page Indicators

Row(
    modifier = Modifier.fillMaxWidth(),
    horizontalArrangement = Arrangement.Center
) {
    repeat(totalItems) { index ->
        Spacer(modifier = Modifier.width(6.dp))
        Box(
            modifier = Modifier
                .size(6.dp)
                .background(
                    color = if (index == currentPos) IND1Dark else IND1Light,
                    shape = CircleShape
                )
        )
    }
}

Creates a row of page indicators (Box composable) based on the totalItems. The current position currentPos determines the color of the active indicator.

@Composable
fun NextButton(title: String, onClick: () -> Unit, isEnabled: Boolean = true) {
    Button(
        onClick = onClick,
        enabled = isEnabled,
        modifier = Modifier
            .padding(16.dp)
            .fillMaxWidth(),
        colors = ButtonDefaults.buttonColors(
            containerColor = b2()
        )
    ) {
        Text(
            text = title,
            fontFamily = latoFamily,
            fontWeight = FontWeight.Bold,
        )
    }
}

NextButton Composable Function

This is a Composable function named NextButton that displays a button with the following parameters:

Button Composable Usage

This uses the Button composable to create a clickable button with the following attributes:

The button also utilizes custom colors defined by ButtonDefaults.buttonColors.

Okay, so now the component work is all done. We have to call the above compose function in our activity/fragment.

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun ShowHorizontalPager() {

    val context = LocalContext.current as? Activity
    val onboardingViewModel = viewModel(modelClass = OnboardingViewModel::class.java)
    val onboardingState = onboardingViewModel.onboardingState.collectAsState()
    val coroutineScope = rememberCoroutineScope()

    val totalPage = remember { mutableIntStateOf(0) }

    totalPage.intValue = onboardingState.value?.screens?.size ?: 0

    val pagerState = rememberPagerState(0) { totalPage.intValue }

    HorizontalPager(state = pagerState, userScrollEnabled = false, modifier = Modifier.fillMaxSize()) {
        onboardingState.value?.screens?.getOrNull(it)?.let { page ->
            OnboardingPage(onboarding = page, onClick = {
                coroutineScope.launch {
                    if (pagerState.currentPage == pagerState.pageCount - 1) {
                        onboardingViewModel.updateShownOnboardingVersions()
                        Intent(context, MainActivity::class.java).apply {
                            context?.startActivity(this)
                            context?.finish()
                        }
                    } else {
                        pagerState.animateScrollToPage(page = pagerState.currentPage + 1)
                    }
                }
            }, totalItems = pagerState.pageCount, currentPos = it)
        }
    }

    LaunchedEffect(key1 = Unit) {
        onboardingViewModel.fetchOnboarding()
    }
}

ShowHorizontalPager Composable Function

The ShowHorizontalPager function is a Composable that displays a horizontal pager for onboarding screens.

Key Components:

State and Pager Management:

HorizontalPager:

Asynchronous Onboarding Fetch:

back

tags: Kotlin - Android - Jetpack - Compose

Made with 💻 in India