Slide 1

Slide 1 text

Foldable対応 Sansan株式会社 技術本部 Eight Engineering Unit Mobile Application グループ 古川 真次

Slide 2

Slide 2 text

写真が入ります 古川 真次 Sansan株式会社 Eight Engineering Unit Mobile Applicationグループ - 大阪府在住 - 趣味:勉強会の主催 - GDG Osaka オーガナイザー - 経歴 - 2019年12月入社:Sansanアプリ開発 - 2022年1月〜:Eightアプリ開発 - 2022年6月〜:マネジャー

Slide 3

Slide 3 text

Foldable端末とは - 端末を開閉することができる(Fold-able)端末 - スマホを縦半分に折りたためるFlip、 折りたたむとスマホサイズになるFoldがある https://news.samsung.com/jp/galaxy-z-flip6-olympic-edition- paris-2024 https://consumer.huawei.com/cn/phones/mate-xt-ultimate-design/

Slide 4

Slide 4 text

Foldable端末対応 How-To - 開く、閉じるでonConfigurationChanged() が呼ばれる - 「開いている or 閉じている」はJetpack WindowManagerの FoldingFeatureを使えば取得可能 - ディスプレイ接合部の座標なども取れるため、左側・右側で表示を変え られる

Slide 5

Slide 5 text

アプリをFoldable対応するには - listDetailPaneScaffoldを利用すると簡単に実現が可能(experimental) - https://developer.android.com/develop/ui/compose/layouts/adaptive/list-detail https://developer.android.com/develop/ui/compose/layouts/adaptive/list-detail https://developer.android.com/jetpack/androidx/releases/compose -material3-adaptive

Slide 6

Slide 6 text

具体的な実装

Slide 7

Slide 7 text

実装 @Composable fun MainViewScreen(userList: List) { val navigator = rememberListDetailPaneScaffoldNavigator() BackHandler(navigator.canNavigateBack()) { navigator.navigateBack() } ListDetailPaneScaffold( directive = navigator.scaffoldDirective, value = navigator.scaffoldValue, listPane = { AnimatedPane { UserList(userList = userList, onItemClicked = { item -> navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, item) }) } }, detailPane = { AnimatedPane { navigator.currentDestination?.content?.let { UserDetail(it) } } } ) }

Slide 8

Slide 8 text

実装 @Composable fun MainViewScreen(userList: List) { val navigator = rememberListDetailPaneScaffoldNavigator() BackHandler(navigator.canNavigateBack()) { navigator.navigateBack() } ListDetailPaneScaffold( directive = navigator.scaffoldDirective, value = navigator.scaffoldValue, listPane = { AnimatedPane { UserList(userList = userList, onItemClicked = { item -> navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, item) }) } }, detailPane = { AnimatedPane { navigator.currentDestination?.content?.let { UserDetail(it) } } } ) }

Slide 9

Slide 9 text

実装 @Composable fun MainViewScreen(userList: List) { val navigator = rememberListDetailPaneScaffoldNavigator() BackHandler(navigator.canNavigateBack()) { navigator.navigateBack() } ListDetailPaneScaffold( directive = navigator.scaffoldDirective, value = navigator.scaffoldValue, listPane = { AnimatedPane { UserList(userList = userList, onItemClicked = { item -> navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, item) }) } }, detailPane = { AnimatedPane { navigator.currentDestination?.content?.let { UserDetail(it) } } } ) } リストのPane

Slide 10

Slide 10 text

実装 @Composable fun MainViewScreen(userList: List) { val navigator = rememberListDetailPaneScaffoldNavigator() BackHandler(navigator.canNavigateBack()) { navigator.navigateBack() } ListDetailPaneScaffold( directive = navigator.scaffoldDirective, value = navigator.scaffoldValue, listPane = { AnimatedPane { UserList(userList = userList, onItemClicked = { item -> navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, item) }) } }, detailPane = { AnimatedPane { navigator.currentDestination?.content?.let { UserDetail(it) } } } ) } リストのPane

Slide 11

Slide 11 text

実装 @Composable fun MainViewScreen(userList: List) { val navigator = rememberListDetailPaneScaffoldNavigator() BackHandler(navigator.canNavigateBack()) { navigator.navigateBack() } ListDetailPaneScaffold( directive = navigator.scaffoldDirective, value = navigator.scaffoldValue, listPane = { AnimatedPane { UserList(userList = userList, onItemClicked = { item -> navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, item) }) } }, detailPane = { AnimatedPane { navigator.currentDestination?.content?.let { UserDetail(it) } } } ) } 詳細画面のPane

Slide 12

Slide 12 text

実装 @Composable fun MainViewScreen(userList: List) { val navigator = rememberListDetailPaneScaffoldNavigator() BackHandler(navigator.canNavigateBack()) { navigator.navigateBack() } ListDetailPaneScaffold( directive = navigator.scaffoldDirective, value = navigator.scaffoldValue, listPane = { AnimatedPane { UserList(userList = userList, onItemClicked = { item -> navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, item) }) } }, detailPane = { AnimatedPane { navigator.currentDestination?.content?.let { UserDetail(it) } } } ) } 表示箇所の保持

Slide 13

Slide 13 text

実装 @Composable fun MainViewScreen(userList: List) { val navigator = rememberListDetailPaneScaffoldNavigator() BackHandler(navigator.canNavigateBack()) { navigator.navigateBack() } ListDetailPaneScaffold( directive = navigator.scaffoldDirective, value = navigator.scaffoldValue, listPane = { AnimatedPane { UserList(userList = userList, onItemClicked = { item -> navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, item) }) } }, detailPane = { AnimatedPane { navigator.currentDestination?.content?.let { UserDetail(it) } } } ) } 戻るボタンを サポート

Slide 14

Slide 14 text

実装 @Composable fun MainViewScreen(userList: List) { val navigator = rememberListDetailPaneScaffoldNavigator() BackHandler(navigator.canNavigateBack()) { navigator.navigateBack() } ListDetailPaneScaffold( directive = navigator.scaffoldDirective, value = navigator.scaffoldValue, listPane = { AnimatedPane { UserList(userList = userList, onItemClicked = { item -> navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, item) }) } }, detailPane = { AnimatedPane { navigator.currentDestination?.content?.let { UserDetail(it) } } } ) }

Slide 15

Slide 15 text

- listDetailPaneScaffoldを使えば50行くらいでサンプルが作れるくらい簡単 - FoldingFeatureを駆使するとディスプレイの折り目も避けられる まとめ

Slide 16

Slide 16 text

仲間を募集しています https://open.talentio.com/r/1/c/sansan/pages/76400 https://jp.corp-sansan.com/mimi/2024/07/interview-100 Androidエンジニア 東京・大阪・福岡