Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
2019_9_18Reject.pdf
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
[email protected]
September 18, 2019
Programming
570
3
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
2019_9_18Reject.pdf
iOS13の新しいAPIであるCompositional LayoutsとDiffable Data Sourcesについての発表です。
[email protected]
September 18, 2019
More Decks by
[email protected]
See All by
[email protected]
TSPLのすすめ
shiz
1
340
Swift compiler 101 & How async function works
shiz
0
130
Swiftコンパイラ超入門+async関数の仕組み
shiz
0
390
複雑さに立ち向かうための ソフトウェア開発入門
shiz
3
2.4k
座談会 「Strict ConcurrencyとSwift 6が開く新時代: 私たちはどう生きるか?」
shiz
5
17k
(非公開スライド追加)座談会 「Strict ConcurrencyとSwift 6が開く新時代: 私たちはどう生きるか?」
shiz
1
800
複雑さに立ち向かうためのコードリーディング入門
shiz
35
15k
Swift Observation
shiz
5
950
Swift Reflection
shiz
1
310
Other Decks in Programming
See All in Programming
LL言語やWebフレームワークのPostgreSQL対応 〜DBの機能がユーザーに届くまで〜
kentaroutakeda
1
150
テストを司るデーモンに会いに行く 〜隔離した仮想マシンでテストを通すまで〜
h1d3mun3
1
360
そのリトライ、死んだコネクションを使い回していませんか ── GoのHTTPクライアントとHTTP/2を実プロダクト障害から学び直す
myus4a
0
140
手動確認はもう限界 〜XCUITestでCustom URL Schemeの遷移を起動種別ごとに自動テストする〜 / Testing Custom URL Schemes with XCUITest
otouto
0
280
GKE で Pod の見方を変えたら、スケールアウト時の挙動を真に捉えられた話
stkk
0
120
一人だけ、Kiroが静止する日
hideg
0
110
「新人AI禁止のその先へ ― 参加と協働のステップアップ」Vibe TOKYO, AI & CRAFT / 2026年8月21日
kentarowada
0
100
SONY CISC-NEWS NWS-1750 + NWB-225 フレームバッファの NetBSD/news68k ドライバ実装 / OSC2026Hiroshima
tsutsui
0
110
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
370
更なる可用性を求めて、5年間運用したKotlinのアプリケーションをGoでリプレイスする話
ken_tunc
0
230
App Storeの外へ──日本のiOSサイドローディング入門 for iOSDC Japan 2026
yuukiw00w
0
210
市販E-Readerを乗っ取れ 〜Embedded Swiftで電子ペーパーガジェットを制御する〜
trickart
0
190
Featured
See All Featured
The State of eCommerce SEO: How to Win in Today's Products SERPs - #SEOweek
aleyda
2
12k
Impact Scores and Hybrid Strategies: The future of link building
tamaranovitovic
0
440
The Curse of the Amulet
leimatthew05
3
14k
What does AI have to do with Human Rights?
axbom
PRO
1
2.4k
Avoiding the “Bad Training, Faster” Trap in the Age of AI
tmiket
0
240
Crafting Experiences
bethany
1
340
How to Align SEO within the Product Triangle To Get Buy-In & Support - #RIMC
aleyda
2
1.8k
For a Future-Friendly Web
brad_frost
183
10k
The Director’s Chair: Orchestrating AI for Truly Effective Learning
tmiket
1
300
SEO in 2025: How to Prepare for the Future of Search
ipullrank
3
3.8k
Docker and Python
trallard
47
4.2k
Product Roadmaps are Hard
iamctodd
55
13k
Transcript
J04%$3FKFDU$POGFSFODF ࣌ͷมԽʹԠͯ͡ ਐԽ͢Δ $PMMFDUJPO7JFX ը૾ࢀরϦϯΫ
VISITS Technologiesגࣜձࣾ shiz@stzn3 shiz(ͣ͠) @shiz stzn(shiz) ։ൃܦݧݴޠ: Swift Kotlin Javascript
PHP C# Java Go… iOSDC Japan 2019 ίΞελοϑ
$PNQPTJUJPOBM-BZPVUT %J⒎BCMF%BUB4PVSDFT ը૾ࢀরϦϯΫ
$PNQPTJUJPOBM -BZPVUT ը૾ࢀরϦϯΫ
എܠ ը૾ࢀরϦϯΫ
J04ͷ"QQ4UPSF
None
None
6*$PMMFDUJPO7JFX -BZPVU நΫϥε υΩϡϝϯτ্ αϒΫϥε͕ඞཁ https://developer.apple.com/documentation/uikit/uicollectionviewlayout
6*$PMMFDUJPO7JFX 'MPX-BZPVU ߦϕʔεͷϨΠΞτ γϯϓϧͳઃఆ ڞ௨σβΠϯͰ෯͘ར༻
ϋʔυΣΞͷਐԽ ωοτϫʔΫͷ্ Ұͭͷը໘Ͱදࣔ͢Δ߲ͷ૿Ճ ϨΠΞτͷෳࡶԽ
ʑͷ ଟͷϘΠϥʔϓϨʔτ͕ඞཁ ύϑΥʔϚϯεͷߟྀ͕ඞཁ όονϔομʔɺϑολʔͷ ઃఆ͕ࠔ 4FMG4J[JOHͷܭࢉ͕ෳࡶ
$PNQPTJUJPOBM -BZPVUT খ͞ͳ෦ΛΈ߹ΘͤΔ ॊೈʹΧελϚΠζՄೳ ૣ͘ɺਖ਼֬ͳαΠζͷࣗಈܭࢉ
̐ͭͷཁૉ 4J[F
class NSCollectionLayoutDimension { class func fractionalWidth(_ fractionalWidth: CGFloat) -> Self
class func fractionalHeight(_ fractionalHeight: CGFloat) -> Self } ͷίϯϙʔωϯτͷ αΠζʹର͢Δׂ߹Ͱࢦఆ /4$PMMFDUJPO-BZPVU4J[F https://developer.apple.com/documentation/uikit/nscollectionlayoutsize
class NSCollectionLayoutDimension { class func absolute(_ absoluteDimension: CGFloat) -> Self
class func estimated(_ estimatedDimension: CGFloat) -> Self } ϙΠϯτͰࢦఆ /4$PMMFDUJPO-BZPVU4J[F https://developer.apple.com/documentation/uikit/nscollectionlayoutsize
class NSCollectionLayoutDimension { class func absolute(_ absoluteDimension: CGFloat) -> Self
class func estimated( _ estimatedDimension: CGFloat) -> Self } /4$PMMFDUJPO-BZPVU4J[F https://developer.apple.com/documentation/uikit/nscollectionlayoutsize
https://developer.apple.com/documentation/uikit/nscollectionlayoutitem 4J[FΛࢦఆ͢Δ $FMM)FBEFSɺ'PPUFSͳͲ
ϨΠΞτͷجຊ୯Ґ https://developer.apple.com/documentation/uikit/nscollectionlayoutgroup
*UFNͷͻͱ͔ͨ·Γ https://developer.apple.com/documentation/uikit/nscollectionlayoutgroup
ΫϩʔδϟͰॳظԽ https://developer.apple.com/documentation/uikit/nscollectionlayoutgroup
Ұͭͷ(SPVQΛࢦఆ (SPVQʹՃใΛࢦఆ https://developer.apple.com/documentation/uikit/nscollectionlayoutsection
https://developer.apple.com/documentation/uikit/uicollectionviewcompositionallayout https://developer.apple.com/documentation/appkit/nscollectionviewcompositionallayout
https://developer.apple.com/documentation/uikit/uicollectionviewcompositionallayout https://developer.apple.com/documentation/appkit/nscollectionviewcompositionallayout Ұͭͷ4FDUJPOΛࢦఆ
https://developer.apple.com/documentation/uikit/uicollectionviewcompositionallayout https://developer.apple.com/documentation/appkit/nscollectionviewcompositionallayout ΫϩʔδϟͰ 4FDUJPO͝ͱͷఆٛՄೳ
αϯϓϧίʔυ Ͱ֬ೝ
-JTU7JFX$POUSPMMFS
private func createLayout() -> UICollectionViewLayout { let itemSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(1.0)) let item = NSCollectionLayoutItem( layoutSize: itemSize) let groupSize = NSCollectionLayoutSize( widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(44)) let group = NSCollectionLayoutGroup.horizontal( layoutSize: groupSize, subitems: [item]) let section = NSCollectionLayoutSection( group: group) let layout = UICollectionViewCompositionalLayout( section: section) return layout }
private func createLayout() -> UICollectionViewLayout { let itemSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(1.0)) let item = NSCollectionLayoutItem( layoutSize: itemSize) let groupSize = NSCollectionLayoutSize( widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(44)) let group = NSCollectionLayoutGroup.horizontal( layoutSize: groupSize, subitems: [item]) let section = NSCollectionLayoutSection( group: group) let layout = UICollectionViewCompositionalLayout( section: section) return layout } ᶃ4J[FΛܾΊΔ
private func createLayout() -> UICollectionViewLayout { let itemSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(1.0)) let item = NSCollectionLayoutItem( layoutSize: itemSize) let groupSize = NSCollectionLayoutSize( widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(44)) let group = NSCollectionLayoutGroup.horizontal( layoutSize: groupSize, subitems: [item]) let section = NSCollectionLayoutSection( group: group) let layout = UICollectionViewCompositionalLayout( section: section) return layout } ᶄ4J[FΛࢦఆͯ͠*UFNΛ࡞Δ
private func createLayout() -> UICollectionViewLayout { let itemSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(1.0)) let item = NSCollectionLayoutItem( layoutSize: itemSize) let groupSize = NSCollectionLayoutSize( widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(44)) let group = NSCollectionLayoutGroup.horizontal( layoutSize: groupSize, subitems: [item]) let section = NSCollectionLayoutSection( group: group) let layout = UICollectionViewCompositionalLayout( section: section) return layout } ᶅ4J[Fͱ*UFNΛࢦఆͯ͠ (SPVQΛ࡞
private func createLayout() -> UICollectionViewLayout { let itemSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(1.0)) let item = NSCollectionLayoutItem( layoutSize: itemSize) let groupSize = NSCollectionLayoutSize( widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(44)) let group = NSCollectionLayoutGroup.horizontal( layoutSize: groupSize, subitems: [item]) let section = NSCollectionLayoutSection( group: group) let layout = UICollectionViewCompositionalLayout( section: section) return layout } ᶆ(SPVQΛࢦఆͯ͠ 4FDUJPOΛ࡞
private func createLayout() -> UICollectionViewLayout { let itemSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(1.0)) let item = NSCollectionLayoutItem( layoutSize: itemSize) let groupSize = NSCollectionLayoutSize( widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(44)) let group = NSCollectionLayoutGroup.horizontal( layoutSize: groupSize, subitems: [item]) let section = NSCollectionLayoutSection( group: group) let layout = UICollectionViewCompositionalLayout( section: section) return layout } ᶇ4FDUJPOΛࢦఆͯ͠ -BZPVUΛ࡞
(SJE7JFX$POUSPMMFS
private func createLayout() -> UICollectionViewLayout { let itemSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(0.2), heightDimension: .fractionalHeight(1.0)) let item = NSCollectionLayoutItem(layoutSize: itemSize) let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.2), heightDimension: .fractionalWidth(1.0)) let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item]) let section = NSCollectionLayoutSection(group: group) let layout = UICollectionViewCompositionalLayout(section: section) return layout } ॎˋɺԣˋ (SJE7JFX$POUSPMMFS
private func createLayout() -> UICollectionViewLayout { let itemSize = NSCollectionLayoutSize(widthDimension:
.fractionalWidth(0.2), heightDimension: .fractionalHeight(1.0)) let item = NSCollectionLayoutItem(layoutSize: itemSize) let groupSize = NSCollectionLayoutSize( widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalWidth(0.2)) let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item]) let section = NSCollectionLayoutSection(group: group) let layout = UICollectionViewCompositionalLayout(section: section) return layout } ॎʹԣͷˋ (SJE7JFX$POUSPMMFS
(SJE7JFX$POUSPMMFS
func createLayout() -> UICollectionViewLayout { let itemSize = NSCollectionLayoutSize( widthDimension:
.fractionalWidth(1.0), heightDimension: .fractionalHeight(1.0)) let item = NSCollectionLayoutItem(layoutSize: itemSize) let groupSize = NSCollectionLayoutSize( widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(44)) let group = NSCollectionLayoutGroup.horizontal( layoutSize: groupSize, subitem: item, count: 2) let spacing = CGFloat(10) group.interItemSpacing = .fixed(spacing) let section = NSCollectionLayoutSection(group: group) section.interGroupSpacing = spacing section.contentInsets = NSDirectionalEdgeInsets( top: 0, leading: 10, bottom: 0, trailing: 10) let layout = UICollectionViewCompositionalLayout(section: section) return layout } 5XP$PMVNO7JFX$POUSPMMFS ΞΠςϜΛʹࢦఆ ॎɺԣ
5XP$PMVNO7JFX$POUSPMMFS
DistinctSectionsViewController
func createLayout() -> UICollectionViewLayout { let layout = UICollectionViewCompositionalLayout {
(sectionIndex: Int, layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? in guard let sectionLayoutKind = ɹ SectionLayoutKind(rawValue: sectionIndex) else { ɹɹ return nil ɹ} let columns = sectionLayoutKind.columnCount let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(1.0)) let item = NSCollectionLayoutItem(layoutSize: itemSize) item.contentInsets = NSDirectionalEdgeInsets(top: 2, leading: 2, bottom: 2, trailing: 2) let groupHeight = columns == 1 ? NSCollectionLayoutDimension.absolute(44) : NSCollectionLayoutDimension.fractionalWidth(0.2) let groupSize = NSCollectionLayoutSize( ɹɹɹɹɹɹɹɹɹɹɹɹɹ widthDimension: .fractionalWidth(1.0), heightDimension: groupHeight) let group = NSCollectionLayoutGroup.horizontal( layoutSize: groupSize, subitem: item, count: columns) let section = NSCollectionLayoutSection(group: group) section.contentInsets = NSDirectionalEdgeInsets(top: 20, leading: 20, bottom: 20, trailing: 20) return section } return layout } DistinctSectionsViewController 4FDUJPO͝ͱʹ ϨΠΞτΛఆٛ
func createLayout() -> UICollectionViewLayout { let layout = UICollectionViewCompositionalLayout {
(sectionIndex: Int, layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? in guard let sectionLayoutKind = ɹ SectionLayoutKind(rawValue: sectionIndex) else { ɹɹ return nil ɹ} let columns = sectionLayoutKind.columnCount let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(1.0)) let item = NSCollectionLayoutItem(layoutSize: itemSize) item.contentInsets = NSDirectionalEdgeInsets(top: 2, leading: 2, bottom: 2, trailing: 2) let groupHeight = columns == 1 ? NSCollectionLayoutDimension.absolute(44) : NSCollectionLayoutDimension.fractionalWidth(0.2) let groupSize = NSCollectionLayoutSize( ɹɹɹɹɹɹɹɹɹɹɹɹɹ widthDimension: .fractionalWidth(1.0), heightDimension: groupHeight) let group = NSCollectionLayoutGroup.horizontal( layoutSize: groupSize, subitem: item, count: columns) let section = NSCollectionLayoutSection(group: group) section.contentInsets = NSDirectionalEdgeInsets(top: 20, leading: 20, bottom: 20, trailing: 20) return section } return layout } DistinctSectionsViewController 4FDUJPOʹԠͯ͡ΧϥϜΛมߋ
ItemBadgeSupplementaryViewController
func createLayout() -> UICollectionViewLayout { let badgeAnchor = NSCollectionLayoutAnchor( edges:
[.top, .trailing], fractionalOffset: CGPoint(x: 0.3, y: -0.3)) let badgeSize = NSCollectionLayoutSize(widthDimension: .absolute(20), heightDimension: .absolute(20)) let badge = NSCollectionLayoutSupplementaryItem( layoutSize: badgeSize, elementKind: ItemBadgeSupplementaryViewController.badgeElementKind, containerAnchor: badgeAnchor) let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.25), heightDimension: .fractionalHeight(1.0)) let item = NSCollectionLayoutItem(layoutSize: itemSize, supplementaryItems: [badge]) item.contentInsets = NSDirectionalEdgeInsets(top: 5, leading: 5, bottom: 5, trailing: 5) let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalWidth(0.2)) let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item]) let section = NSCollectionLayoutSection(group: group) section.contentInsets = NSDirectionalEdgeInsets(top: 20, leading: 20, bottom: 20, trailing: 20) let layout = UICollectionViewCompositionalLayout(section: section) return layout } ItemBadgeSupplementaryViewController
func createLayout() -> UICollectionViewLayout { let badgeAnchor = NSCollectionLayoutAnchor(edges: [.top,
.trailing], fractionalOffset: CGPoint(x: 0.3, y: -0.3)) let badgeSize = NSCollectionLayoutSize(widthDimension: .absolute(20), heightDimension: .absolute(20)) let badge = NSCollectionLayoutSupplementaryItem( layoutSize: badgeSize, elementKind: ItemBadgeSupplementaryViewController .badgeElementKind, containerAnchor: badgeAnchor) let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.25), heightDimension: .fractionalHeight(1.0)) let item = NSCollectionLayoutItem(layoutSize: itemSize, supplementaryItems: [badge]) item.contentInsets = NSDirectionalEdgeInsets(top: 5, leading: 5, bottom: 5, trailing: 5) let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalWidth(0.2)) let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item]) let section = NSCollectionLayoutSection(group: group) section.contentInsets = NSDirectionalEdgeInsets(top: 20, leading: 20, bottom: 20, trailing: 20) let layout = UICollectionViewCompositionalLayout(section: section) return layout } ItemBadgeSupplementaryViewController SupplementaryItemΛ࡞
func createLayout() -> UICollectionViewLayout { let badgeAnchor = NSCollectionLayoutAnchor(edges: [.top,
.trailing], fractionalOffset: CGPoint(x: 0.3, y: -0.3)) let badgeSize = NSCollectionLayoutSize(widthDimension: .absolute(20), heightDimension: .absolute(20)) let badge = NSCollectionLayoutSupplementaryItem( layoutSize: badgeSize, elementKind: ItemBadgeSupplementaryViewController.badgeElementKind, containerAnchor: badgeAnchor) let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.25), heightDimension: .fractionalHeight(1.0)) let item = NSCollectionLayoutItem( layoutSize: itemSize, supplementaryItems: [badge]) item.contentInsets = NSDirectionalEdgeInsets(top: 5, leading: 5, bottom: 5, trailing: 5) let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalWidth(0.2)) let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item]) let section = NSCollectionLayoutSection(group: group) section.contentInsets = NSDirectionalEdgeInsets(top: 20, leading: 20, bottom: 20, trailing: 20) let layout = UICollectionViewCompositionalLayout(section: section) return layout } ItemBadgeSupplementaryViewController Itemʹࢦఆ
ItemBadgeSupplementaryViewController
OrthogonalScrollingViewController
func createLayout() -> UICollectionViewLayout { let layout = UICollectionViewCompositionalLayout {
(sectionIndex: Int, layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? in let leadingItem = NSCollectionLayoutItem(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.7), heightDimension: .fractionalHeight(1.0))) leadingItem.contentInsets = NSDirectionalEdgeInsets(top: 10, leading: 10, bottom: 10, trailing: 10) let trailingItem = NSCollectionLayoutItem(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(0.3))) trailingItem.contentInsets = NSDirectionalEdgeInsets(top: 10, leading: 10, bottom: 10, trailing: 10) let trailingGroup = NSCollectionLayoutGroup.vertical(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.3), heightDimension: .fractionalHeight(1.0)), subitem: trailingItem, count: 2) let containerGroup = NSCollectionLayoutGroup.horizontal( layoutSize: NSCollectionLayoutSize( widthDimension: .fractionalWidth(0.85), heightDimension: .fractionalHeight(0.4)), subitems: [leadingItem, trailingGroup]) let section = NSCollectionLayoutSection(group: containerGroup) section.orthogonalScrollingBehavior = .continuous return section } return layout } (SPVQͷதʹ(SPVQΛೖΕΔ OrthogonalScrollingViewController
func createLayout() -> UICollectionViewLayout { let layout = UICollectionViewCompositionalLayout {
(sectionIndex: Int, layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? in let leadingItem = NSCollectionLayoutItem(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.7), heightDimension: .fractionalHeight(1.0))) leadingItem.contentInsets = NSDirectionalEdgeInsets(top: 10, leading: 10, bottom: 10, trailing: 10) let trailingItem = NSCollectionLayoutItem(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(0.3))) trailingItem.contentInsets = NSDirectionalEdgeInsets(top: 10, leading: 10, bottom: 10, trailing: 10) let trailingGroup = NSCollectionLayoutGroup.vertical(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.3), heightDimension: .fractionalHeight(1.0)), subitem: trailingItem, count: 2) let containerGroup = NSCollectionLayoutGroup.horizontal(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.85), heightDimension: .fractionalHeight(0.4)), subitems: [leadingItem, trailingGroup]) let section = NSCollectionLayoutSection( group: containerGroup) section.orthogonalScrollingBehavior = .continuous return section } return layout } OrthogonalScrollingViewController ωετ͞Εͨ(SPVQͷ εΫϩʔϧͷಈ͖ΛௐͰ͖Δ
OrthogonalScrollBehaviorViewController
%J⒎BCMF %BUB4PVSDFT
എܠ ը૾ࢀরϦϯΫ
%BUB 4PVSDF 6* OVNCFS0G4FDUJPOT OVNCFS0G*UFNT *O4FDUJPO DFMM'PS*UFN"U
%BUB 4PVSDF 6* EJE$IBOHF 8FC4FSWJDF 3FTQPOTF
%BUB 4PVSDF 6* <$FMM> <%BUB> *OEFY1BUI
QFSGPSN#BUDI6QEBUFT collectionView.performBatchUpdates({ var deletes = [Int]() var inserts = [(person:Person,
index:Int)]() … for deletedIndex in deletes.sorted().reversed() { people.remove(at: deletedIndex) } let sortedInserts = inserts.sorted(by: { (personA, personB) -> Bool in return personA.index <= personB.index }) for insertion in sortedInserts { people.insert(insertion.person, at: insertion.index) } IUUQTEFWFMPQFSBQQMFDPNEPDVNFOUBUJPOVJLJUVJDPMMFDUJPOWJFXDVTUPNJ[JOH@DPMMFDUJPO@WJFX@MBZPVUT DIBOHFTMBUFTU@NJOPS ॱ൪Λؒҧ͑Δͱ ΤϥʔʹͳΔ߹
%J⒎BCMF %BUB4PVSDFT γϯϓϧͳ࣮ σʔλͷҰݩཧ ύϑΥʔϚϯεΛ࠷దԽ
/4%J⒎BCMF%BUB4PVSDF 4OBQTIPU 6*ͱσʔλΛཧ͢Δ།Ұͷଘࡏ 4JOHMF4PVSDFPG5SVUI *OEFY1BUIΛΘͳ͍ class NSDiffableDataSourceSnapshot<SectionIdentifierType, ItemIdentifierType> where
SectionIdentifierType : Hashable, ItemIdentifierType : Hashable
αϯϓϧίʔυ Ͱ֬ೝ
.PVOUBJOT7JFX$POUSPMMFS
6*ͷߋ৽ εςοϓ func performQuery(with filter: String?) { let mountains =
mountainsController .filteredMountains(with: filter) .sorted { $0.name < $1.name } let snapshot = NSDiffableDataSourceSnapshot<Section, Mountain>() snapshot.appendSections([.main]) snapshot.appendItems(mountains) dataSource.apply(snapshot, animatingDifferences: true) } ͭͷεςοϓΛ౿Ή͚ͩͰઃఆ͕Ͱ͖Δ .PVOUBJOT7JFX$POUSPMMFS
func performQuery(with filter: String?) { let mountains = mountainsController .filteredMountains(with:
filter) .sorted { $0.name < $1.name } let snapshot = NSDiffableDataSourceSnapshot<Section, Mountain>() snapshot.appendSections([.main]) snapshot.appendItems(mountains) dataSource.apply(snapshot, animatingDifferences: true) } .PVOUBJOT7JFX$POUSPMMFS 1. ৽͍͠Snapshotͷੜ
func performQuery(with filter: String?) { let mountains = mountainsController.filteredMountains(with: filter)
.sorted { $0.name < $1.name } let snapshot = NSDiffableDataSourceSnapshot<Section, Mountain>() snapshot.appendSections([.main]) snapshot.appendItems(mountains) dataSource.apply(snapshot, animatingDifferences: true) } .PVOUBJOT7JFX$POUSPMMFS 2. ߋ৽͍ͨ͠ใͷՃ
func performQuery(with filter: String?) { let mountains = mountainsController.filteredMountains(with: filter)
.sorted { $0.name < $1.name } let snapshot = NSDiffableDataSourceSnapshot<Section, Mountain>() snapshot.appendSections([.main]) snapshot.appendItems(mountains) dataSource.apply( snapshot, animatingDifferences: true) } .PVOUBJOT7JFX$POUSPMMFS 3. applyͷݺͼग़͠
4FDUJPO .PVOUBJO enum Section: CaseIterable { case main } struct
Mountain: Hashable { let name: String let height: Int let identifier = UUID() func hash(into hasher: inout Hasher) { hasher.combine(identifier) } static func == (lhs: Mountain, rhs: Mountain) -> Bool { return lhs.identifier == rhs.identifier } } .PVOUBJOT7JFX$POUSPMMFS
%BUB4PVSDFͷઃఆ func configureDataSource() { dataSource = UICollectionViewDiffableDataSource <Section, MountainsController.Mountain> (collectionView:
mountainsCollectionView) { (collectionView: UICollectionView, indexPath: IndexPath, mountain: MountainsController.Mountain) -> UICollectionViewCell? in guard let mountainCell = collectionView.dequeueReusableCell( withReuseIdentifier: LabelCell.reuseIdentifier, for: indexPath) as? LabelCell else { fatalError("Cannot create new cell") } mountainCell.label.text = mountain.name return mountainCell } } .PVOUBJOT7JFX$POUSPMMFS
ΫϩʔδϟͰηϧͷઃఆํ๏Λࢦఆ func configureDataSource() { dataSource = UICollectionViewDiffableDataSource <Section, MountainsController.Mountain> (collectionView:
mountainsCollectionView) { (collectionView: UICollectionView, indexPath: IndexPath, mountain: MountainsController.Mountain) -> UICollectionViewCell? in guard let mountainCell = collectionView.dequeueReusableCell( withReuseIdentifier: LabelCell.reuseIdentifier, for: indexPath) as? LabelCell else { fatalError("Cannot create new cell") } mountainCell.label.text = mountain.name return mountainCell } } .PVOUBJOT7JFX$POUSPMMFS
func configureDataSource() { dataSource = UICollectionViewDiffableDataSource <Section, MountainsController.Mountain> (collectionView: mountainsCollectionView)
{ (collectionView: UICollectionView, indexPath: IndexPath, mountain: MountainsController.Mountain) -> UICollectionViewCell? in guard let mountainCell = collectionView.dequeueReusableCell( withReuseIdentifier: LabelCell.reuseIdentifier, for: indexPath) as? LabelCell else { fatalError("Cannot create new cell") } mountainCell.label.text = mountain.name return mountainCell } } IndexPathΛ༻͍ͯ͠ͳ͍ .PVOUBJOT7JFX$POUSPMMFS
8J'J4FUUJOHT7JFX$POUSPMMFS
ηΫγϣϯ͕ෳ͋Δ func updateUI(animated: Bool = true) { … currentSnapshot.appendSections([.config]) currentSnapshot.appendItems(configItems,
toSection: .config) if controller.wifiEnabled { let sortedNetworks = controller.availableNetworks.sorted { $0.name < $1.name } let networkItems = sortedNetworks.map { Item(network: $0) } currentSnapshot.appendSections([.networks]) currentSnapshot.appendItems(networkItems, toSection: .networks) } self.dataSource.apply(currentSnapshot, animatingDifferences: animated) } 8J'J4FUUJOHT7JFX$POUSPMMFS ηΫγϣϯ͝ͱʹΛઃఆ͢Δ
*OTFSUJPO4PSU7JFX$POUSPMMFS
ඞཁͳͱ͜Ζ͚ͩߋ৽͢Δ func performSortStep() { let updatedSnapshot = dataSource.snapshot() updatedSnapshot.sectionIdentifiers.forEach {
let section = $0 if !section.isSorted { section.sortNext() let items = section.values updatedSnapshot.deleteItems(items) updatedSnapshot.appendItems(items, toSection: section) sectionCountNeedingSort += 1 } } … } ݱࡏͷ4OBQTIPUͷঢ়ଶΛऔಘ *OTFSUJPO4PSU7JFX$POUSPMMFS
func performSortStep() { let updatedSnapshot = dataSource.snapshot() updatedSnapshot.sectionIdentifiers.forEach { let
section = $0 if !section.isSorted { section.sortNext() let items = section.values updatedSnapshot.deleteItems(items) updatedSnapshot.appendItems( items, toSection: section) sectionCountNeedingSort += 1 } } … } ඞཁͳͱ͜ΖͷΈߋ৽ *OTFSUJPO4PSU7JFX$POUSPMMFS
*OTFSUJPO4PSU7JFX$POUSPMMFS
ύϑΥʔϚϯε %J⒎ͷܭࢉ0 O BQQMZϝιουܭࢉ݁ՌΛϝΠ ϯΩϡʔͰฦ٫ ʹՃ࣮ෆཁͰόοΫάϥϯ υͰॲཧ͕Մೳ
·ͱΊ ը૾ࢀরϦϯΫ
એݴతͰ౷Ұతͳ"1* ϚϧνϓϥοτϑΥʔϜରԠ ϑϨʔϜϫʔΫͰཧ ڞ௨తͳಛ
ݕ౼͍͖͍ͯͨ͜͠ͱ ΧελϚΠζͲ͜·ͰՄೳʁ 4XJGU6*ͱͷ࿈ܞ
ͰJ04Ҏ߱ʜ
https://github.com/kishikawakatsumi/IBPCollectionViewCompositionalLayout *#1$PMMFDUJPO7JFX $PNQPTJUJPOBM-BZPVU
%J⒎BCMF%BUB4PVSDFT https://github.com/ra1028/DiffableDataSources
IUUQTRJJUBDPNTIJ[JUFNTBBCGFE
͋Γ͕ͱ͏ ͍͟͝·ͨ͠ ը૾ࢀরϦϯΫ