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
ScrollView scroll,decelerating - iOS SDK UIkit
Search
notoroid
September 25, 2021
Programming
3
300
ScrollView scroll,decelerating - iOS SDK UIkit
札幌iPhoneアプリ開発懇談会(Devsap) 2021年9月25日勉強会資料
notoroid
September 25, 2021
Tweet
Share
More Decks by notoroid
See All by notoroid
GeometryReader - SwiftUI
notoroid
0
43
iOS 26 SDKの新機能 (liquid抜き) - iOS26orLaterUpdateAndSceneForUIKit
notoroid
0
130
UIテスト自動化サポート- Testbed for XCUIAutomation practice
notoroid
0
190
UIViewController - Interactive PopGesture
notoroid
0
56
Xcodeショートカット 2025年版
notoroid
0
75
ZIPでくれ - Apple謹製 geocoding/ reverse geocoding
notoroid
0
110
WeatherKit iOS18 update - お天気の更新
notoroid
0
92
AppIntentsの用途 - AppleのGPT元年
notoroid
1
190
Privacy manifests - Appleと開発コミュニティ
notoroid
1
250
Other Decks in Programming
See All in Programming
ソフトウェア設計の実践的な考え方
masuda220
PRO
4
660
Six and a half ridiculous things to do with Quarkus
hollycummins
0
210
pnpm に provenance のダウングレード を検出する PR を出してみた
ryo_manba
1
160
Android16 Migration Stories ~Building a Pattern for Android OS upgrades~
reoandroider
0
140
マンガアプリViewerの大画面対応を考える
kk__777
0
260
NixOS + Kubernetesで構築する自宅サーバーのすべて
ichi_h3
0
1.2k
When Dependencies Fail: Building Antifragile Applications in a Fragile World
selcukusta
0
110
Google Opalで使える37のライブラリ
mickey_kubo
3
150
iOSでSVG画像を扱う
kishikawakatsumi
0
170
GC25 Recap: The Code You Reviewed is Not the Code You Built / #newt_gophercon_tour
mazrean
0
110
他言語経験者が Golangci-lint を最初のコーディングメンターにした話 / How Golangci-lint Became My First Coding Mentor: A Story from a Polyglot Programmer
uma31
0
420
Devoxx BE - Local Development in the AI Era
kdubois
0
140
Featured
See All Featured
Music & Morning Musume
bryan
46
6.9k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
32
1.7k
Principles of Awesome APIs and How to Build Them.
keavy
127
17k
The Invisible Side of Design
smashingmag
302
51k
Building Better People: How to give real-time feedback that sticks.
wjessup
369
20k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.6k
Side Projects
sachag
455
43k
The Straight Up "How To Draw Better" Workshop
denniskardys
238
140k
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.2k
Making the Leap to Tech Lead
cromwellryan
135
9.6k
The World Runs on Bad Software
bkeepers
PRO
72
11k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
658
61k
Transcript
*SJNBTV%FOTBO1MBOOJOHೳొཁ 4DSPMM7JFX6*,JU 4DSPMM %FDFMFSBUJOH
iOS15ެ։͞Ε·ͨ͠
J04Y͔Βͷڧ੍Ξοϓσʔτͳ͍ͨΊΞοϓ σʔτ͘ͳ͍ͷͷɺΞϓϦ։ൃऀଆʹ ͱͬͯϓϩάϥϛϯά͘͢͠ͳΔΈ͕ಋೖ
async/await/actorͷಋೖʹΑΓεϨουؒͰͷॲ ཧΛؾʹ͢Δඞཁ͕ݮΓSwiftUI(ͱ͍͏͔iOSωΠ ςΟϒΞϓϦ։ൃ)ͷֶशίετ͕Լ͕Γ·ͨ͠ɻ
SwiftUI Λొͷࠒ(2019)͔ Βਪ͍ͯ͠ΔํͰ͕͢ɺ
͜͜ΖSwiftUIΛΕ UIKit ʹ͍ͬͯͨɻ
Կނ
6*,JUͰΓͨ͜͜͠ ͱ͕͋Δ͔Βͩ ຊԻ 4XJGU6*Ͱཉ͍͕͠4XJGU6*Ͱ࣮ݱͰ͖ͳ͍͔Β
*OGJOJU-PPQ)FBEFS ແݶʹεΫϩʔϧͰ͖Δϔομ w ࠨӈํʹεΫϩʔϧՄೳ w ϝχϡʔ͕ແݶʹදࣔ͞Ε ͍ͯΔΑ͏ʹϔομ߲͕ εΫϩʔϧ w தԝʹ͋Δ߲͕બத
w ϠΫΦΫΞϓϦ ݄ݱࡏ ͷϝχϡʔ
*OGJOJU-PPQ)FBEFS w ແݶϧʔϓϔομʔΦʔϓϯιʔεϕʔεͰ͍͔ͭ͘ଘࡏ w 6*$PMMFDUJPO7JFXϕʔε w %BUB4PVSDFEFMFHBUFΛͬͯಈతʹΧϥϜੜ w ݸͷϝχϡʔ߲Λදࣔ͢Δ͚ͩͰ6*$PMMFDUJPO7JFXΛ͏ඞ ཁ͕͋Δͷ͔
w ͬͱγϯϓϧʹ ͭ·Γ6*4DSPMM7JFX Ͱ࣮ݱͰ͖ͳ͍͔
6*4DSPMMʹ͍ͭͯ ߟ͑ͯΈΔ
6*4DSPMM7JFX J04ͷ͍ͪ͝͝ͷྑ͞Λܾఆ͚ͮͨ6*ύʔπ w J04 J1IPOF04 ͷࠒ͔Βଘࡏ w Ϣʔβʔͷλονૢ࡞ʹਵ͢ΔεΫϩʔϧ w
ίϯςϯπ·Ͱ౸ୡͨ͠ࡍͷόϯε w Ԡ༻6*ଟ w 8,8FC7JFXɺ6*5BCMF7JFXɺ6*$PMMFDUJPO7JFX w աڈʹ.BQ༻
6*4DSPMM7JFX J04ͷ͍ͪ͝͝ͷྑ͞Λܾఆ͚ͮͨ6*ύʔπ w ΞϓϦ։ൃͰෳࡶͳΈ w εΫϩʔϧίϯςϯπͷ෯ߴ͞ͷऔѻ͕ʑมԽ w "VUP4J[JOHˠ$POTUSBJOUˠ"ODIPSͱʑཧ w
ίϯςϯπྖҬͷτϥϒϧ w J04ʙεςʔλεόʔྖҬมߋΛΖʹड͚Δ w εςʔλεόʔ͔ΒϊονྖҬͱมԽ w ෳϓϩύςΟͷΈ߹ΘͤͰڍಈ͕มԽ w %FMFHBUFͰͷදࣔྖҬ੍ޚͷϊϋඞཁ
6*4DSPMM7JFXͱੜΫϥε w 6*,JUయܕతͳΫϥεϥ ΠϒϥϦ w ੜݩΫϥεͷػೳΛੜ ݩ্͕ॻ͖͢Δ w ੜ͕܁Γฦ͞ΕΔͱຊདྷ ͷػೳ͕͑Δ͔Ѳͮ͠
Β͘ͳΔ ੜݩ ੜઌ
6*4DSPMM7JFXͷػೳ্ॻ͖ঢ়گ 6*4DSPMM7JFXͷੜΫϥεͰԿ͕͑Δ͔ ߟ͑Δඞཁ͋Γ
6*4DSPMM7JFXͷػೳ্ॻ͖ঢ়گ 6*4DSPMM7JFXͷੜΫϥεͰԿ͕͑Δ͔ ߟ͑Δඞཁ͋Γ EFMFHBUF༻Մೳ δΣενϟʔҎ֎֓Ͷ ར༻Մೳ
6*4DSPMM7JFX%FMFHBUF 6*4DSPMM7JFXͰͷΠϕϯτΛัଊ͢ΔEFMFHBUF w 4DSPMMΠϕϯτ w εΫϩʔϧ։࢝ऴྃΠϕϯτ w ར༻ऀ6*ଆͷશͯͷεΫϩʔϧΠϕϯτ͕ൃੜ w ζʔϜ։࢝ऴྃΠϕϯτ
w %FDFMFSBUJOH։࢝ऴྃΠϕϯτ w Ϣʔβʔͷૢ࡞ޙʹόϯυಈ࡞ͷ։࢝ऴྃΛ௨ w εΫϩʔϧΛτοϓʹҠಈ͢Δ͔ͷΠϕϯτ εςʔλεྖҬͷλ οϓ
6*4DSPMM7JFX%FMFHBUF 4DSPMMͱ%FDFMFSBUJOHͷؔ w 4DSPMMΠϕϯτ w Ϣʔβʔ͕λονૢ࡞Ͱ w %FDFMFSBUJOHΠϕϯτ w
Ճ͋Γͷλονૢ࡞ޙʹɺ4DSPMM7JFX͕ຊདྷ͋Δ͖Ґஔ ʹίϯςϯπ͕Δ·ͰͷΠϕϯτ w %FDFMFSBUJOH͕ऴྃ͢Δ·Ͱը໘্ͷಈ͖ࢭ·Βͳ͍
͜͜·ͰΛ౿·͑ͯ ແݶϧʔϓΛ࣮ݱ͢Δ
αϯϓϧίʔυ
IUUQTHJUIVCDPNOPUPSPJE *OGJOJUF)FBEFS%FNP
6*4DSPMM7JFXͰແݶεΫϩʔϧΛ࣮ݱᶃ 4DSPMMຖʹҐஔௐɺ%FDFMFSBUJOHޙʹਖ਼نԽ
6*4DSPMM7JFXͰແݶεΫϩʔϧΛ࣮ݱᶄ 4DSPMMຖʹҐஔௐɺ%FDFMFSBUJOHޙʹਖ਼نԽ
6*4DSPMM7JFXͰແݶεΫϩʔϧΛ࣮ݱᶄ 4DSPMMຖʹҐஔௐɺ%FDFMFSBUJOHޙʹਖ਼نԽ JO fi OJUF-PPQ7JFX্ͷ4UBDL7JFXͷ9࣠Λௐ ͯ͠ݶΓ͋ΔϔομཁૉΛ࠶ར༻͢Δ JO fi OJUF-PPQ7JFX4DSPMM7JFX੍͕ޚ͢Δ
6*4DSPMM7JFXͰແݶεΫϩʔϧΛ࣮ݱᶅ 4DSPMMຖʹҐஔௐɺ%FDFMFSBUJOHޙʹਖ਼نԽ 4DSPPM7JFXͷྖҬΛϔομʔͷΧϥϜ ෯ͱ͠ɺDMJQ5P#PVOEΛ֦͛ͯࢠཁૉΛ දࣔɺλονՄೳͳྖҬ֦͓͛ͯ͘
extension InfiniteLoopHeaderView: UIScrollViewDelegate { … // DeceleratingͷରԠ func scrollViewDidEndDecelerating(_ scrollView:
UIScrollView) { // εΫϩʔϧҐஔͷਖ਼نԽ͕ߦΘΕ͍ͯͳ͍߹ guard scrollNormalizedPosition != 0 else { return } // ίϯςϯπͷதԝҐஔΛऔಘ let scrollViewCenter = scrollView.superview!.convert(scrollView.center, to: contentView) // தԝҐஔؚ͕·ΕΔۣܗใΛݩʹϔομʔཁૉͷΠϯσοΫεΛܭࢉ var targetIndex: Int = -1 for index in 0..<(leftOverrun + elementCount + rightOverrun) { let hitTestRect = CGRect(origin: CGPoint(x: CGFloat(index) * scrollView.bounds.width, y: 0), size: scrollView.bounds.size) if hitTestRect.contains(scrollViewCenter) { targetIndex = index } } // ಘΒΕͨΠϯσοΫεΛݩʹΠϯσοΫεใΛਖ਼نԽ let position = targetIndex - leftOverrun let loopIndex = (elementCount + ( (position) % elementCount)) % elementCount selectedIndex = loopIndex // ͜͜ͰεΫϩʔϧॲཧΛϓϩςΫτ͢Δ(scrollNormalizedPosition͕มߋ͞Εͯ͠·͏ՄೳੑΛආ͚ΔͨΊ) skipDidScroll = true self.scrollView.contentOffset = CGPoint(x: self.scrollView.bounds.width * CGFloat(centerForFiniteLoop() + selectedIndex), y: 0) skipDidScroll = false scrollNormalizedPosition = 0 centerXConstraint.constant = 0 } }
extension InfiniteLoopHeaderView: UIScrollViewDelegate { … // εΫϩʔϧͷରԠ func scrollViewDidScroll(_ scrollView:
UIScrollView) { // skipDidScroll͞Ε͍ͯΔ߹scrollViewDidEndDecelerating Ͱͷ guard skipDidScroll != true else { return } // ScrollViewͷcontentOffsetͱscrollNormalizedPosition͔ΒҐஔΛಘΔ let plainPosition = Int(ceil( (scrollView.contentOffset.x / scrollView.bounds.width) - CGFloat(centerForFiniteLoop()) + CGFloat(scrollNormalizedPosition) ) ) if plainPosition <= leftSafeArea { // ϔομʔࠨͷ҆શྖҬΛ͍͑ͯͨ߹scrollNormalizedPosition ʹҐஔΛ֨ೲ͠contentView ͷҐஔΛͣΒ͢ scrollNormalizedPosition = scrollNormalizedPosition + -plainPosition + (elementCount - visibleColumnNumber) centerXConstraint.constant = CGFloat(-scrollNormalizedPosition) * scrollView.bounds.width } else if plainPosition >= rightSafeArea { // ϔομʔӈͷ҆શྖҬΛ͍͑ͯͨ߹scrollNormalizedPosition ʹҐஔΛ֨ೲ͠contentView ͷҐஔΛͣΒ͢ scrollNormalizedPosition = scrollNormalizedPosition + -plainPosition centerXConstraint.constant = CGFloat(-scrollNormalizedPosition) * scrollView.bounds.width } else { // ͦͷଞͷ߹௨ৗॲཧɻબΠϯσοΫεΛมߋ let lIndex = (elementCount + (plainPosition % elementCount)) % elementCount selectedIndex = lIndex } } }
·ͱΊ
·ͱΊ w4XJGU6*Ͱ࣮ݱͰ͖ͳ͍6*Λ6*,JUͰ࡞Γ·ͨ͠ wΦʔϓϯιʔεطଘͷͷΑΓγϯϓϧͳ6*ύʔπ Λࢦ͠·ͨ͠ w6*ύʔπΛ࡞ʹ6*4DSPMM7JFXΛ༻͠·ͨ͠ w6*4DSPMM7JFXͷ4DSPMMΠϕϯτϢʔβʔૢ࡞ɺՃ ʹΑΔόϯυؔͳ͠ʹൃੜ͠·͢ w6*4DSPMM7JFX͕શʹ੩ࢭ͢Δͷ%FDFMFSBUJOH ΠϕϯτऴྃޙͰ͢