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
15
iOS17のScrollViewはちょっとできる子
toya108
September 06, 2024
Tweet
Share
More Decks by toya108
See All by toya108
MaintainabilityIndexを 計測しながらコードの保守性を 改善している話
toya108
1
790
Featured
See All Featured
Gamification - CAS2011
davidbonilla
81
5.4k
How STYLIGHT went responsive
nonsquared
100
5.7k
Building a Modern Day E-commerce SEO Strategy
aleyda
42
7.4k
Learning to Love Humans: Emotional Interface Design
aarron
273
40k
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
53
2.9k
Understanding Cognitive Biases in Performance Measurement
bluesmoon
29
1.8k
StorybookのUI Testing Handbookを読んだ
zakiyama
30
5.9k
Rails Girls Zürich Keynote
gr2m
95
14k
The Pragmatic Product Professional
lauravandoore
35
6.8k
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
7
770
Bash Introduction
62gerente
613
210k
How To Stay Up To Date on Web Technology
chriscoyier
790
250k
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書きます!!