Share
Embed
iOS/Android間でUI実装を近づけるヒントと道標
potatotips#90での登壇資料になります。
Androidと同じ形でいけそうに見えるが実はそうではない?なUI実装事例を紹介しています。
本資料では「1.テキスト入力に関する事例」「2.Chipを使った表現事例」「3.Scrollが関連する表現事例」の3点を題材にして、意外と類似していそうで、実際はそうではない点がある事に注意が必要なものに関する解説をしています。
純正のComponentで提供されている要素により注意深く目を向け、Scrollに関するiOS/Android間での違いを押さえるという2点がポイントになると考えています。
Fumiya Sakai
January 28, 2025
Transcript
19 slides
-
自己紹介 ・Fumiya Sakai ・Mobile Application Engineer アカウント: ・Twitter: https://twitter.com/fumiyasac ・Facebook:
https://www.facebook.com/fumiya.sakai.37 ・Github: https://github.com/fumiyasac ・Qiita: https://qiita.com/fumiyasac@github 発表者: ・Born on September 21, 1984 これまでの歩み: Web Designer 2008 ~ 2010 Web Engineer 2012 ~ 2016 App Engineer 2017 ~ Now iOS / Android / sometimes Flutter -
UI実装であると嬉しいレシピブックの最新情報 UI実装であると嬉しいレシピブックVol.3として2022年10月に商業化しました! Still WIP これまでの同人誌として頒布したものに加えて、Vol.1及びVol.2に頒布したものの 中で書籍に載せきれなかったものや表現や動きが特徴的でユーザーにもほんの少し 遊び心を与える様なUI実装を紹介したものをVol.3としています。 概要: これからの構想: こちらで購入可能です:
Amazon / Google Play / Apple Books / KINOKUNIYA / Rakuten BOOKS etc.. 🏊 iOS: SwiftUIを利用したUI実装や動画関連の実装 🏊 Android: Jetpack Composeの基本やその他気になるUI表現の考察 -
技術書同人誌博覧会スタッフ&デザイン協力もしてます (御礼)第11回技術書同人誌博覧会参加ありがとうございました! 🍀 #9 一般参加募集チラシ 🍀 #10 次回案内チラシ 🍀 #11
次回案内チラシ 🍀 技書博 mini OSC案内 -
Androidではできるけど…iOSでは少し工夫が必要? Androidと同じ形でいけそうに見えるが実はそうではない?な事例紹介 意外と類似していそうで、実際はそうではない点がある事に注意 1. テキスト入力に関する事例: ユーザーの入力値の長さや改行に合わせて、入力フォームが伸縮する様な処理については、仕様次第では結構似ている形で作成 する事ができる場合もある。 2. Chipを使った表現事例: AndroidではCategory表示・TagCloud表示の様な文字サイズが異なるChip表示をする場合は純正のComponentが準備されている
が、iOSではUICollectionView等を利用して工夫をする必要がある。 3. Scrollが関連する表現事例: AndroidのCoordinatorLayoutやNestedScrollViewを利用する事で、Scroll変化量を取得して位置によって表示を変化させる表現 は類似した様な表現をiOSではAnimation等を上手にりようしたカスタマイズが必要になる。 -
改行や長文テキスト入力に関する事例 Webでもよくある様な入力エリアが伸縮する様なフォームを考えてみます Ξϯέʔτͷճೖྗ ͍ͭ͋Γ͕ͱ͏͍͟͝·͢ɻ 初期状態では1行だけの表示になる。 ͪ͜Β͕͕ॻ͍ͨ࠷ॳͷετʔϦʔʹͳΓ ·͢ɻॳΊͯग़ձ͑ͨͷ͜ͷॴ͔ΒͰ͠ ͨɻͦͷ࣌·ͩ·ͩۦ͚ग़͠ͷ৽ਓͰͨ͠ 入力量が増えると下へ伸びるイメージ Ξϯέʔτͷճೖྗ
Android OutlinedTextFieldを利用する事で実現可能。 Box( modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.TopCenter ) { var sampleText by remember { mutableStateOf(… テキストが入ります …) } OutlinedTextField( value = sampleText, onValueChange = { sampleText = it }, modifier = … , singleLine = false, maxLines = 7, … ) } https://developer.android.com/develop/ui/compose/text/user-input?hl=ja 参考コード例: ※この様に定めると、最大7行分まで伸縮する -
@Composable fun FliterChipEachRow( chipList: List<String>, tempList: Set<Int> ) { var
multipleChecked by rememberSavable { mutableStateOf(tempList) } FlowRow(… modifier/mainAxisSpacing/crossAxisSpacing等を設定する …) { chipList.forEachIndexed { index, s -> FilterChip( selected = … multipleChecked内で判定する …, onClick = { … multipleCheckedを増減させて見た目を切り替える … }, label = Text(text: s), border = … 状態によって見た目を変更する …, leadingIcon = … 状態によって見た目を変更する …, shape = RoundedCornerShape(8.dp) ) } } } Category表示・TagCloud表示の様なChip表示 文字の長さに合わせて上手く折り返す様なChip表示をする場合を考えてみます $IJQϑΟϧλʔαϯϓϧ Android FilterChipを利用する事で実現可能。 https://developer.android.com/develop/ui/compose/layouts/flow?hl=ja ※FilterChip & FlowRowを組み合わせて作る ✔︎ Chip1 Chip2 ✔︎ Chip3 Chip4 ✔︎ Chip5 https://developer.android.com/develop/ui/compose/components/chip?hl=ja FilterChipの他にも様々な形でのChip表示が 純正Componentとして準備されています。 デザインに合わせたある程度のカスタマイズ もする事ができます。 -
(補足)iOSで自前で全てを作成する以外の選択肢 UIKitを利用している際は、UICollectionViewをカスタマイズして作成する https://www.youtube.com/watch?v=dKe59TavIEc Tag CollectionView in Swift 5: iOS UICollectionViewでレイアウト属性をカスタマイズ
※レイアウト属性に関する実装が難しい 宣言的UIの登場によって従来よりも作成しやすくなっ たUI表現の1つかもしれない… -
Scrollが関連する様な動きを実装する際のポイント CoordinatorLayoutを利用したHeader要素を折りたたむ様な表現を実装する 上方向へScrollするとTitle表記位置と背景イメージが隠れる表現: هࣄαϯϓϧλΠτϧ ˡ ˡ هࣄαϯϓϧλΠτϧ XML(Android View)を利用したLayout階層 -
CoordinatorLayout - AppBarLayour - NestedScrollView - CollapsingToolbarLayout ・ImageView ・Toolbar - RecyclerView app:layout_scrollFlags =“scrll|exitUntilCollapsed” app:layout_collapseMode =“parallax” app:layout_collapseMode =“pin” ※iOSの場合はUIScrollViewDelegate & AutoLayoutの制約更新で実現する。 純正Component(UI要素)を組み合わせる事によって実現可能である -
StickyHeaderの様な表現を実現する際の構造例 LazyColumn内のstickyHeaderを利用して構築する点が大きなポイント 上方向へScrollするとTab要素が残り続ける表現: λΠτϧ هࣄҰཡ χϡʔε هࣄҰཡ χϡʔε λΠτϧ @Composable
fun ExampleScreen(…) { … 必要な処理を設定する … LazyColumn { item { … 上Scrollで隠れる対象要素を配置する … } sticyHeader { … 吸着するView要素を配置する … } when (tabSelected) { … 切り替え可能なScreen要素を配置する … } } } https://blog.studysapuri.jp/entry/2023/2/15/sticky-tab-header 参考: Jetpack ComposeでタブをSticky Headerにする方法 ※Tab要素は残り続ける -
UIKitを利用した場合における類似した構成を作る場合 View要素の重なりにも配慮しなければいけないため結構難しい画面となる Storyboardによる概要と構成はこの様なイメージになります: λΠτϧ هࣄҰཡ χϡʔε هࣄҰཡ χϡʔε λΠτϧ ScrollView
DetailHeaderView DetailSwitchButtonView UIStackView UITableView(1) UITableView(2) -
類似した表現をSwiftUIで作成する際の構成 DroidKaigi2023で実装されていた事例を応用して作成したサンプルになります LazyVStackと配置したSection要素やUI構造を工夫する必要がある: λΠτϧ هࣄҰཡ χϡʔε هࣄҰཡ χϡʔε λΠτϧ https://github.com/fumiyasac/LikeCoodinatorLayoutExample
SectionHeader要素のボタ ン背景に対するAnimation はGeometryReaderを利用し て実施する。 Offset値を監視してその値を 引き渡す。@Stateの変化を利 用して高さを変更する。 SwiftUIで作成する場合は、 LazyVStackを利用して作成す る点がポイントになる。 -
Scroll変化量を取得して反映するNestedScrollを利用 NestedScrollを利用してScroll前後の運動量や速度を取得可能である Profile画面の配置要素がBar内にAnimationを伴って位置変更をする: ˡ XML(Jetpack Compose)を利用したLayout階層 - BoxConstraints - Box
.nestedScroll(nestedScrollConnection) val nestedScrollConnection = remember { … scroll前の運動量保持 Profileのサムネイル画像と名前がHeaderのBar要素まで吸い込まれていく NestedScroll + Swipable + MotionLayoutの組み合わせ } onPreSecroll onPostSecroll onPostFling … scroll後の運動量保持 … scroll速度の反映 -
(補足)iOSで自前で全てを作成する以外の選択肢 SwiftUIではGeometryReaderや.matchedGeometryEffet等でカスタマイズをする https://www.youtube.com/watch?v=2NMjFuiZ5Po SwiftUI Animated Sticky Header: iOS そもそもはComponentとして提供はされていない ※調整に関する計算が煩雑になりがち
GeometryReaderを活用した座標計算やScrollViewReader に加え.matchedGeometryEffect等に関する理解が必要 -
まとめ 考え方が異なる点やポイントを押さえておく事で慌てない様にする 必ずしも全ての見え方を合わせる事が正解とは限らない。適材適所でどうするかを考える。 1. 純正のComponentで提供されている要素により注意深く目を向けてみる: Androidでは純正Componentとして提供されているが、iOSではそうではない物もありますし、またはその逆のパターンである場合 もあります。その様な際には別の形で提供する方法や便利なOSS活用も視野に入れると良さそうに思います。 2. Scrollに関するiOS/Android間での違いを押さえておく: 特にScrollに関連する処理については、iOS/Android間で考え方や方針が大きく異なる場合が多いです。特にScrollを利用した複
雑なUI実装を要する場合には、それぞれの特性にうまく合わせた形を模索する必要があると思います。 3. Scroll表現や複雑なUI実装をする画面構造を紐解く楽しさ: 複雑なUI実装に対して向き合う事は決して簡単な事ではありませんが「なぜその様な方針や構成を取るのか?」という点に対し て詳細やポイントになり得る点を見抜く事によって表現の幅が広がっていくと思います。