2021/05/28

Jetpack composeでBottom Navigation(TabBar)をお試し実装

jetpack-composekotlin

チュートリアルレベルで、Jetpack composeのBottom Navigationを実装してみました。

Navigating with Composeをみてやってみました。

libraryのインストール

dependencies {
    // この行を追加
    implementation "androidx.navigation:navigation-compose:2.4.0-alpha01"
}

composableの実装

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            YourProjectTheme {
                // A surface container using the 'background' color from the theme
                Surface(color = MaterialTheme.colors.background) {
                    App()
                }
            }
        }
    }
}

sealed class Screen(val route: String, @StringRes val resourceId: Int, val icon: ImageVector) {
    // need to define string resource definitions of [profile and friends_list]
    object Profile : Screen("profile", R.string.profile, Icons.Filled.AccountCircle)
    object FriendsList : Screen("friendslist", R.string.friends_list, Icons.Filled.Favorite)
}

@Composable
fun App() {
    val navController = rememberNavController()
    val items = listOf(
        Screen.Profile,
        Screen.FriendsList,
    )
    Scaffold(
        bottomBar = {
            BottomNavigation {
                val navBackStackEntry by navController.currentBackStackEntryAsState()
                val currentRoute = navBackStackEntry?.destination?.route
                items.forEach { screen ->
                    BottomNavigationItem(
                        icon = { Icon(imageVector = screen.icon, contentDescription = screen.route) },
                        label = { Text(stringResource(screen.resourceId)) },
                        selected = currentRoute == screen.route,
                        onClick = {
                            navController.navigate(screen.route) {
                                // Pop up to the start destination of the graph to
                                // avoid building up a large stack of destinations
                                // on the back stack as users select items
                                navController.graph.startDestinationRoute?.let {
                                    popUpTo(it) {
                                        saveState = true
                                    }
                                }
                                // Avoid multiple copies of the same destination when
                                // reselecting the same item
                                launchSingleTop = true
                                // Restore state when reselecting a previously selected item
                                restoreState = true
                            }
                        }
                    )
                }
            }
        }
    ) {
        NavHost(navController, startDestination = Screen.Profile.route) {
            composable(Screen.Profile.route) { Profile(navController) }
            composable(Screen.FriendsList.route) { FriendsList(navController) }
        }
    }
}

@Composable
fun Profile(navController: NavHostController) {
    Text(text = "profile")
}

@Composable
fun FriendsList(navController: NavHostController) {
    Text(text = "friends")
}
  • 見た目をカスタマイズするにはBottomNavigationのcontent領域をうまくゴニョゴニョしてあげれば変更できそうでした。
  • deep linkやネストした遷移にも対応しているようでした。

navigation-composeライブラリに頼らずに遷移を自分自身で実装する場合には、public final OnBackPressedDispatcher getOnBackPressedDispatcher()を使って(ハードの)戻るボタンを押した時の動作をうまくハンドリングしてあげるのを忘れないようにしないといけないようです。

以上です。