【Android Studio】サブモジュールのGitが表示されない
はじめに
Android Studioで、サブモジュールのGitが表示されない場合の対策を解説。
方法
左上のAndroid Studio→Settings…→Version Control→Directory Mappings→サブモジュールを追加
【Android Jetpack Compose】ModalBottomSheet使用時、ステータスバーの文字色調整
はじめに
Android Jetpack ComposeでModalBottomSheetを使用した際、ステータスバーの色が変更されることがある。
※ステータスバーとは、画面上部に表示されるアイコン(時刻・バッテリー残量など)が並んだ領域のこと。

原因
ModalBottomSheetメソッド内でisAppearanceLightStatusBarsの値を変更しているのが原因。
WindowCompat.getInsetsController(window, window.decorView).apply {
isAppearanceLightStatusBars = !darkThemeEnabled
isAppearanceLightNavigationBars = !darkThemeEnabled
}
※androidx.compose.material3:material3-android:1.3.1ライブラリを使用(2024年12月時点で最新版)
対策
ModalBottomSheetメソッドのcontent内で、再度isAppearanceLightStatusBarsの値を変更させる。(LocalView.current.parent as DialogWindowProvider).windowでwindowを取得するのがポイント。
ModalBottomSheet(
onDismissRequest = { showBottomSheet = false },
sheetState = sheetState
) {
//ステータスバーを変更
val window = (LocalView.current.parent as DialogWindowProvider).window
WindowCompat.getInsetsController(window, window.decorView).isAppearanceLightStatusBars = false
// Sheet content
Button(onClick = {
scope.launch { sheetState.hide() }.invokeOnCompletion {
if (!sheetState.isVisible) showBottomSheet = false
}
}) {
Text("Hide bottom sheet")
}
}
参考サイト
【Android Jetpack Compose】下スワイプで画面を閉じる
はじめに
Android Jetpack Composeで、下スワイプで画面を閉じる方法を解説。ModalBottomSheetを用いる方法もあるが、この記事ではAnchoredDraggableStateによりスワイプ検知して画面を閉じる方法について解説。

方法
1. スワイプ開始・終了クラスの作成
スワイプ状態を定義するクラス作成。
enum class AnchorPos { Start, End; }
2. モーダル画面の作成
モーダル画面を作成
@OptIn(ExperimentalFoundationApi::class) @Composable fun ModalScreen(navController: NavHostController) { val screenHeight = with(LocalDensity.current) { LocalConfiguration.current.screenHeightDp.dp.toPx() } val anchors = DraggableAnchors { AnchorPos.Start at 0f AnchorPos.End at screenHeight } // ドラッグ可能な距離と状態を設定 val draggableState = remember { AnchoredDraggableState( initialValue = AnchorPos.Start, anchors = anchors, positionalThreshold = { it * 0.5f }, velocityThreshold = { screenHeight * 0.5f }, snapAnimationSpec = SpringSpec(), decayAnimationSpec = exponentialDecay(), confirmValueChange = { when (it) { AnchorPos.Start -> {} AnchorPos.End -> { //複数回popが行われることを防ぐため、現在の画面でのみpopを行う。 if (navController.currentDestination?.route == NavItem.MODAL.route) { navController.popBackStack() } } } true } ) } Box( modifier = Modifier .offset { IntOffset( x = 0, y = draggableState .requireOffset() .roundToInt() ) } .anchoredDraggable( state = draggableState, orientation = Orientation.Vertical ) .fillMaxSize() .background(Color.DarkGray), ) { //戻るボタン Button( onClick = { navController.popBackStack() }, colors = ButtonDefaults.buttonColors(containerColor = Color.Transparent), contentPadding = PaddingValues(0.dp) ) { Icon( modifier = Modifier.size(32.dp), contentDescription = "Close", imageVector = Icons.Default.Close ) } } }
参考サイト
【Android Jetpack Compose】ボトムナビゲーション& 複数バックスタックの実装
はじめに
Android Jetpack Composeで、ボトムナビゲーション& 複数バックスタックの実装について解説。
処理の説明
各ボトムタブごとにバックスタックを保持。
例えば、ホーム1→ホーム2→他タブ押下→ホームタブ押下の際、ホーム1に遷移するのではなく、ホーム2に遷移させる。

方法
まず、画面のRoute定義するためNavItemenumクラス作成。
enum class NavItem(val route: String, val icon: ImageVector) { //BottomNavigation HOME("Home", Icons.Default.Home), EMAIL("Email", Icons.Default.Email), SETTINGS("Settings", Icons.Default.Settings), //Screen HOME_1("Home_1", Icons.Default.Home), HOME_2("Home_2", Icons.Default.Home), EMAIL_1("Email_1", Icons.Default.Email), EMAIL_2("Email_2", Icons.Default.Email), SETTINGS_1("Settings_1", Icons.Default.Settings), SETTINGS_2("Settings_2", Icons.Default.Settings) }
次に、画面下に表示させるボトムナビゲーションを作成。
@Composable fun BottomNavigation(navController: NavHostController) { val items = listOf( NavItem.HOME, NavItem.EMAIL, NavItem.SETTINGS ) NavigationBar { val navBackStackEntry by navController.currentBackStackEntryAsState() val currentRoute = navBackStackEntry?.destination?.route items.forEach { item -> NavigationBarItem( icon = { Icon(item.icon, contentDescription = item.route) }, label = { Text(item.route) }, selected = currentRoute?.startsWith(item.route) == true, onClick = { navController.navigate(item.route) { popUpTo(navController.graph.findStartDestination().id) { saveState = true } launchSingleTop = true restoreState = true } } ) } } }
表示画面を作成。
//表示画面 @Composable fun ShowScreen(navController: NavHostController, navItem: NavItem, nextRoute: String?) { Column( modifier = Modifier .fillMaxSize() .padding(top = 360.dp), horizontalAlignment = Alignment.CenterHorizontally ) { Row { //アイコン Icon( modifier = Modifier.size(32.dp), imageVector = navItem.icon, contentDescription = navItem.route ) //テキスト Text( modifier = Modifier.padding(start = 12.dp), text = navItem.route, fontSize = 28.sp ) } if (nextRoute != null) { //進むボタン Button( modifier = Modifier.padding(top = 20.dp), onClick = { navController.navigate(nextRoute) } ) { Text( text = "Next", fontSize = 24.sp ) } } else { //戻るボタン Button( modifier = Modifier.padding(top = 20.dp), onClick = { navController.popBackStack() } ) { Text( text = "Back", fontSize = 24.sp ) } } } }
最後に、画面遷移を作成。
@Composable fun MainApp() { val navController = rememberNavController() Scaffold( //ボトムナビゲーション bottomBar = { BottomNavigation(navController) } ) { innerPadding -> Box(modifier = Modifier.padding(innerPadding)) { NavHost( navController = navController, startDestination = NavItem.HOME.route ) { //ホーム navigation(startDestination = NavItem.HOME_1.route, route = NavItem.HOME.route) { composable(NavItem.HOME_1.route) { ShowScreen(navController, NavItem.HOME_1, NavItem.HOME_2.route) } composable(NavItem.HOME_2.route) { ShowScreen(navController, NavItem.HOME_2, null) } } //Eメール navigation(startDestination = NavItem.EMAIL_1.route, route = NavItem.EMAIL.route) { composable(NavItem.EMAIL_1.route) { ShowScreen(navController, NavItem.EMAIL_1, NavItem.EMAIL_2.route) } composable(NavItem.EMAIL_2.route) { ShowScreen(navController, NavItem.EMAIL_2, null) } } //設定 navigation(startDestination = NavItem.SETTINGS_1.route, route = NavItem.SETTINGS.route) { composable(NavItem.SETTINGS_1.route) { ShowScreen(navController, NavItem.SETTINGS_1, NavItem.SETTINGS_2.route) } composable(NavItem.SETTINGS_2.route) { ShowScreen(navController, NavItem.SETTINGS_2, null) } } } } } }
【Android Jetpack Compose】垂直Sliderの作成
はじめに
Android Jetpack Composeで、垂直Sliderを作成する方法について解説。
方法
graphicsLayerとlayoutを下記のように変更することにより実装できる。
@Composable fun MainView(modifier: Modifier = Modifier) { var value by remember { mutableFloatStateOf(0f) } Slider( modifier = modifier .graphicsLayer { rotationZ = 90f transformOrigin = TransformOrigin(0f, 0f) } .layout { measurable, constraints -> val placeable = measurable.measure( Constraints( minWidth = constraints.minHeight, maxWidth = constraints.maxHeight, minHeight = constraints.minWidth, maxHeight = constraints.maxHeight, ) ) layout(placeable.height, placeable.width) { placeable.place(0, -placeable.height) } }, value = value, onValueChange = { value = it } ) }
