2022年8月20日土曜日

Accompanist の Navigation Material の BottomSheet で表示エリアにおさまるように配置する

Accompanist : Navigation Material
  1. @OptIn(ExperimentalMaterialNavigationApi::class)  
  2. @Composable  
  3. fun MyApp() {  
  4.     val bottomSheetNavigator = rememberBottomSheetNavigator()  
  5.     val navController = rememberNavController(bottomSheetNavigator)  
  6.   
  7.     ModalBottomSheetLayout(bottomSheetNavigator) {  
  8.         MyNavHost(navController)  
  9.     }  
  10. }  
  11.   
  12. @OptIn(ExperimentalMaterialNavigationApi::class)  
  13. @Composable  
  14. fun MyNavHost(navController: NavHostController) {  
  15.     NavHost(  
  16.         navController = navController,  
  17.         startDestination = "home"  
  18.     ) {  
  19.         composable(route = "home") {  
  20.             Button(onClick = {  
  21.                 navController.navigate("sheet")  
  22.             }) {  
  23.                 Text("show bottom sheet")  
  24.             }  
  25.         }  
  26.   
  27.         bottomSheet(route = "sheet") {  
  28.             Box(  
  29.                 contentAlignment = Alignment.Center,  
  30.                 modifier = Modifier.fillMaxSize()  
  31.             ) {  
  32.                 Spacer(  
  33.                     modifier = Modifier  
  34.                         .size(100.dp)  
  35.                         .background(Color.Blue)  
  36.                 )  
  37.             }  
  38.         }  
  39.     }  
  40. }  
この場合、Blue の四角は Bottom Sheet を完全に展開したときの中心に配置されます。
rememberNavController に指定した BottomSheetNavigator は NavHostController の navigatorProvider から取得できます。

BottomSheetNavigator の navigatorSheetState から BottomSheet の offset が取れるので、それを利用すると Blue の四角を BottomSheet の表示されている領域の中心に配置することができます。
  1. @OptIn(ExperimentalMaterialNavigationApi::class)  
  2. @Composable  
  3. fun MyNavHost(navController: NavHostController) {  
  4.     NavHost(  
  5.         navController = navController,  
  6.         startDestination = "home"  
  7.     ) {  
  8.         composable(route = "home") {  
  9.             Button(onClick = {  
  10.                 navController.navigate("sheet")  
  11.             }) {  
  12.                 Text("show bottom sheet")  
  13.             }  
  14.         }  
  15.   
  16.         bottomSheet(route = "sheet") {  
  17.   
  18.             val bottomSheetNavigator = navController.navigatorProvider[BottomSheetNavigator::class]  
  19.             val offset = bottomSheetNavigator.navigatorSheetState.offset.value  
  20.   
  21.             Column {  
  22.                 Box(  
  23.                     contentAlignment = Alignment.Center,  
  24.                     modifier = Modifier  
  25.                         .fillMaxWidth()  
  26.                         .weight(1f)  
  27.                 ) {  
  28.                     Spacer(  
  29.                         modifier = Modifier  
  30.                             .size(100.dp)  
  31.                             .background(Color.Blue)  
  32.                     )  
  33.                 }  
  34.                 with(LocalDensity.current) {  
  35.                     Spacer(modifier = Modifier.height(offset.toDp()))  
  36.                 }  
  37.             }  
  38.         }  
  39.     }  
  40. }  



2022年8月8日月曜日

kotlin coroutines 1.6.4 で TestScope.backgroundScope が追加された

https://github.com/Kotlin/kotlinx.coroutines/releases/tag/1.6.4

background で実行してテスト終了時にキャンセルされる coroutines を起動できます。
いままでは明示的に cancelAndJoin() していたのがいらなくなりますね。

  1. @Test  
  2. fun test() = runTest {  
  3.   
  4.     val list = mutableListOf<SomeValue>()  
  5.   
  6.     val job = launch(UnconfinedTestDispatcher()) {  
  7.         repository.someValueFlow().collect {  
  8.             list.add(it)  
  9.         }  
  10.     }  
  11.   
  12.     ...  
  13.   
  14.     assertEquals(expectedSomeValueList, list)  
  15.   
  16.     job.cancelAndJoin()  
  17. }  
  1. @Test  
  2. fun test() = runTest {  
  3.   
  4.     val list = mutableListOf<SomeValue>()  
  5.   
  6.     backgroundScope.launch(UnconfinedTestDispatcher()) {  
  7.         repository.someValueFlow().collect {  
  8.             list.add(it)  
  9.         }  
  10.     }  
  11.   
  12.     ...  
  13.   
  14.     assertEquals(expectedSomeValueList, list)  
  15. }