Android Jetpack Compose BottomNavigationBar

October 29, 2021

Activity

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.AccountCircle
import androidx.compose.material.icons.filled.Home
import androidx.compose.material.icons.filled.List
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.graphics.vector.ImageVector
import com.luasoftware.journey.ui.theme.JourneyTheme

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            JourneyApp()
        }
    }
}

Screens / Routes

// you can also use sealed class instead of enum
enum class JourneyScreen(
    val icon: ImageVector,
    label: String? = null,
    val body: @Composable ((String) -> Unit) -> Unit
) {
    Home(
        icon = Icons.Filled.Home,
        body = { HomeScreen() }
    ),
    Collections(
        icon = Icons.Filled.List,
        body = { CollectionsScreen() }
    ),
    UserProfile(
        icon = Icons.Filled.AccountCircle,
        label = "Profile",
        body = { UserProfileScreen() }
    );

    val label: String by lazy { label ?: name }

    @Composable
    fun content(onScreenChange: (String) -> Unit) {
        body(onScreenChange)
    }
}

@Composable
fun HomeScreen() {
    Text(text = "Home")
}

@Composable
fun CollectionsScreen() {
    Text(text = "Collections")
}

@Composable
fun UserProfileScreen() {
    Text(text = "Profile")
}

Main Composable

@Composable
fun JourneyApp() {
    JourneyTheme {
        val screens = JourneyScreen.values().toList()
        // remember current screen + survive configuration change
        var currentScreen by rememberSaveable { mutableStateOf(JourneyScreen.Home) }
        Scaffold(
            bottomBar = {
                BottomNavigation {
                    screens.forEach { screen ->
                        BottomNavigationItem(
                            icon = { Icon(imageVector = screen.icon, contentDescription = screen.label) },
                            label = { Text(screen.label) },
                            selected = currentScreen == screen,
                            onClick = { currentScreen = screen }
                        )

                    }
                }
            }
        ) { innerPadding ->
            Box(modifier = Modifier.padding(innerPadding)) {
                currentScreen.content(
                    onScreenChange = { screenName ->
                        currentScreen = JourneyScreen.valueOf(screenName)
                    }
                )
            }
        }
    }
}

References:

This work is licensed under a
Creative Commons Attribution-NonCommercial 4.0 International License.