Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
iOS17のScrollViewはちょっとできる子
Search
toya108
September 06, 2024
0
19
iOS17のScrollViewはちょっとできる子
toya108
September 06, 2024
Tweet
Share
More Decks by toya108
See All by toya108
MaintainabilityIndexを 計測しながらコードの保守性を 改善している話
toya108
1
820
Featured
See All Featured
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
133
19k
BBQ
matthewcrist
89
10k
Automating Front-end Workflow
addyosmani
1371
200k
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
12
1k
Agile that works and the tools we love
rasmusluckow
331
21k
Tips & Tricks on How to Get Your First Job In Tech
honzajavorek
0
440
WENDY [Excerpt]
tessaabrams
9
36k
AI: The stuff that nobody shows you
jnunemaker
PRO
2
270
Efficient Content Optimization with Google Search Console & Apps Script
katarinadahlin
PRO
1
330
How to Align SEO within the Product Triangle To Get Buy-In & Support - #RIMC
aleyda
1
1.4k
Collaborative Software Design: How to facilitate domain modelling decisions
baasie
0
140
VelocityConf: Rendering Performance Case Studies
addyosmani
333
24k
Transcript
iOS17のScrollViewは ちょっとできる子 toya108 / Toya Niibori iOSDC Japan 2024 2024/08/23
TrackB
こんにちは 👋 • クックパッド 所属の • ボルダリング が好きな • 1児の父(もうすぐ
2児) として覚えてもらえると嬉しいです toya108 / Toya Niibori
リール風UI めっちゃ流行ってませんか?
リール風UIって何? 要するにTikTok なんらかのアルゴリズムで推薦される動画、 あるいは画像のコンテンツ上下にスワイプして閲覧 できるUI 気づいたらすぐに時間が溶けるやつ
流行りのこの UI 作ってみたくないですか?
iOS17のScrollViewなら 簡単にできます!
要件から考えてみる • 画面幅いっぱいにコンテンツを表示したい • スワイプでコンテンツを切り替えたい(snap scrollの 挙動にしたい) • どのページにスワイプしたか知りたい
iOS16以前 TabViewを90度、子View側を-90度回転させると実装できる これでもできなくはないが、縦にページングしたいだけなのにやってることが 難しすぎる。 TabView { ForEach(items) { item in
ItemView(item: item) } } .tabViewStyle(PageTabViewStyle()) .rotationEffect(.degrees(90))
https://developer.apple.com/videos/play/wwdc2023/10159
どうBeyondしたか 特に重要なのはTargets and positionsで追加された以下のmodifier達 • containerRelativeFrame(_:alignment:) • scrollTargetBehavior(_:) • scrollTargetLayout(isEnabled:)
• scrollPosition(id:anchor:) これらを使用することでリール風UIが楽に作成できる
ScrollView { LazyVStack { ForEach(items) { item in ItemView(item: item)
} } } .ignoresSafeArea() 子Viewのサイズを ScrollViewのコンテナサイズにしたい iOS16まではGeometryReaderなしで子Viewに対し 親Viewのサイズに依存したサイズを指定する術がなかった
ScrollView { LazyVStack(spacing: 0) { ForEach(items) { item in ItemView(item:
item) .containerRelativeFrame([.horizontal, .vertical]) } } } containerRelativeFrame(_:alignment:) GeometryReaderなしでコンテナのサイズを指定可能に👍 ※GeometryReaderの使用を否定したいわけではない。今回の要件ではより 簡単に使用できるcontainerRelativeFrame(_:alignment:)に軍杯が上がると思う。
Snap scrollの挙動にしたい iOS16までのScrollViewは連続的なスクロールしか できない。 pagingはTabViewの領分だった。
scrollTargetBehavior(_:) ScrollView { ... } .scrollTargetBehavior(.paging) pagingやviewAlignedなど、Viewのサイズや位置を 考慮したoffsetの計算が可能に👍
scrollTargetBehavior(_:) pagingはScrollView自体のサイズを 1ページとして計算する。 ScrollView自体のサイズとコンテンツ 1ページのサイズが等しくない場合は viewAlignedが適している。 ViewAligned Paging ScrollView {
... } .scrollTargetBehavior(.viewAligned(limitBehavior: .always))
scrollTargetLayout(isEnabled:) ScrollView { LazyVStack { ... } .scrollTargetLayout() } .scrollTargetBehavior(.viewAligned(limitBehavior:
.always)) viewAlignedを使う場合は基準となるViewを指定する必要がある。 .scrollTargetLayout(isEnabled:)で指定することができる。
ここまで紹介した 機能を使うとこうなる
どのページにスワイプしたか知りたい ページ番号の表示、ログ送信などの目的で どのページへ移動したか知りたくなる。 .onAppear()で最後に表示されたViewからページを計 算することもできるが、頑張りが必要。 1 2 3 4
@State var scrollPosition: Int? = 0 var body: some View
{ ScrollView { ... } .scrollPosition(id: $scrollPosition) } scrollPosition(id:anchor:) スクロールによって表示されるViewのIDをbindできる。
scrollPosition(id:anchor:) 逆にscrollPositionを上書きすることで指定したidのViewに 移動することも可能 💪 ForEach(Array(items.enumerated()), id: \.element.id) { index, item
in Button("\(index)") { withAnimation { scrollPosition = item.id } } }
できました 🎉🎉
まとめ iOS17のScrollViewなら • 子Viewでコンテナサイズを考慮したサイズを簡単に指定できる • paging、viewAlignedなスクロールが可能 • スクロールして表示されたViewのIDが分かる さらにID指定で特定のViewまでスクロールすることができる これらの機能を使用すればリール風UIも楽に作成可能
※注意: 先にiOS16のサポートを切らないといけない リールはUIを実装するより推薦するアルゴリズムを考える方がむずい
おまけ iOS18でもScrollViewは大幅にアップデートされてる。 来年iOSDCではこのトピックで CFP書きます!!