diff --git a/content/notes/wwdc20/10045.md b/content/notes/wwdc20/10045.md new file mode 100644 index 00000000..e1af4f78 --- /dev/null +++ b/content/notes/wwdc20/10045.md @@ -0,0 +1,231 @@ +--- +contributors: dasauto +--- +# Sample Code +Download the [sample code](https://developer.apple.com/documentation/uikit/views_and_controls/collection_views/implementing_modern_collection_views) to learn more about Modern Collection Views. + +# Diffable Data Source +## Recap + +* Introduced in iOS 13. +* Simplifies UI State. +* Automatic animations. +* No more batch updates. +* More to watch session [220](https://developer.apple.com/videos/play/wwdc2019/220) from WWDC 19: Advances in UI Data Sources. + +## [Section Snapshots](https://developer.apple.com/documentation/uikit/nsdiffabledatasourcesectionsnapshot) +* It encapsulates the data for a single section in a UICollectionView. +* Allow data sources to be more composable into section-sized chunks of data. (It's able to present same data use different layout in different sections.) +* Allow modeling of hierarchical data, which is needed to support rendering outline-style UIs. + +### Examples +![][section_snapshots] + +* Top: Horizontally scrolling section. +* Middle: Outline style section. +* Bottom: List section. + +It composes Diffable Data Source from three distinct section snapshots each representing a single section's content. + +### APIs +```swift +// NSDiffableDataSourceSectionSnapshot + +@available(iOS 14.0, tvOS 14.0, *) +public struct NSDiffableDataSourceSectionSnapshot where ItemIdentifierType : Hashable { + + public init() + + public init(_ snapshot: NSDiffableDataSourceSectionSnapshot) + + public mutating func append(_ items: [ItemIdentifierType], to parent: ItemIdentifierType? = nil) + + public mutating func insert(_ items: [ItemIdentifierType], before item: ItemIdentifierType) + + public mutating func insert(_ items: [ItemIdentifierType], after item: ItemIdentifierType) + + public mutating func delete(_ items: [ItemIdentifierType]) + + public mutating func deleteAll() + + public mutating func expand(_ items: [ItemIdentifierType]) + + public mutating func collapse(_ items: [ItemIdentifierType]) + + public mutating func replace(childrenOf parent: ItemIdentifierType, using snapshot: NSDiffableDataSourceSectionSnapshot) + + public mutating func insert(_ snapshot: NSDiffableDataSourceSectionSnapshot, before item: (ItemIdentifierType)) + + public mutating func insert(_ snapshot: NSDiffableDataSourceSectionSnapshot, after item: (ItemIdentifierType)) + + public func isExpanded(_ item: ItemIdentifierType) -> Bool + + public func isVisible(_ item: ItemIdentifierType) -> Bool + + public func contains(_ item: ItemIdentifierType) -> Bool + + public func level(of item: ItemIdentifierType) -> Int + + public func index(of item: ItemIdentifierType) -> Int? + + public func parent(of child: ItemIdentifierType) -> ItemIdentifierType? + + public func snapshot(of parent: ItemIdentifierType, includingParent: Bool = false) -> NSDiffableDataSourceSectionSnapshot + + public var items: [ItemIdentifierType] { get } + + public var rootItems: [ItemIdentifierType] { get } + + public var visibleItems: [ItemIdentifierType] { get } +} +``` +* Use `append` API to add content to section snapshot. +* The optional parent parameter allows us to create parent-child relationships in the section snapshot. + +```swift +// UICollectionViewDiffableDataSource additions for iOS 14 + +extension UICollectionViewDiffableDataSource { + + func apply(_ snapshot: NSDiffableDataSourceSectionSnapshot, + to section: Section, + animatingDifferences: Bool = true, + completion: (() -> Void)? = nil) + + func snapshot(for section: Section) -> + NSDiffableDataSourceSectionSnapshot +} +``` +Code example: + +```swift +// Example of using snapshots and section snapshots together + +func update(animated: Bool=true) { + + // Add our sections in a specific order + let sections: [Section] = [.recent, .top, .suggested] + var snapshot = NSDiffableDataSourceSnapshot() + snapshot.appendSections(sections) + dataSource.apply(snapshot, animatingDifferences: animated) + + // update each section's data via section snapshots in the existing position + for section in sections { + let sectionItems = items(for: section) + var sectionSnapshot = NSDiffableDataSourceSectionSnapshot() + sectionSnapshot.append(sectionItems) + dataSource.apply(sectionSnapshot, to: section, animatingDifferences:animated) + } +} +``` +### Child snapshots +```swift +let childSnapshot = sectionSnapshot.snapshot(for: parent, includingParent: false) +``` + +### Expanding and collapsing items +* Expansion state is persisted. Expansion state is managed as part of a section snapshot's state. +* Call `apply(_:to)` to commit changes. +* Automatic animations. + +```swift +struct NSDiffableDataSourceSectionSnapshot { + func expand(_ items: [Item]) + func collapse(_ items: [Item]) + func isExpanded(_ item: Item) -> Bool +} +``` + +### [Section snapshot handlers](https://developer.apple.com/documentation/uikit/uicollectionviewdiffabledatasource/3600966-sectionsnapshothandlers) +To be notified about expansion state changes caused by these user interactions. + +```swift +// Section Snapshot Handlers: handling user interactions for expand / collapse state changes + +extension UICollectionViewDiffableDataSource { + + struct SectionSnapshotHandlers { + var shouldExpandItem: ((Item) -> Bool)? + var willExpandItem: ((Item) -> Void)? + + var shouldCollapseItem: ((Item) -> Bool)? + var willCollapseItem: ((Item) -> Void)? + + var snapshotForExpandingParent: ((Item, NSDiffableDataSourceSectionSnapshot) -> NSDiffableDataSourceSectionSnapshot)? + } + + var sectionSnapshotHandlers: SectionSnapshotHandlers + +} +``` +* SectionSnapshotHandlers type is a struct which is generic over item and contains five optional closures. +* If `shouldCollapseItem` return `false`, it will avoid particular parent collapsing the outline. +* `snapshotForExpandingParent` for lazy loading expensive content. + +## Reordering Support +* Automatic snapshot updates. +* Transactions. + +### [Reordering Handlers](https://developer.apple.com/documentation/uikit/uicollectionviewdiffabledatasource/reorderinghandlers) +To be notified that a user-initiated reordering interaction took place so that it can persist the new visual order to the application's backing store, which is its final source of truth. + +```swift +// Diffable Data Source Reordering Handlers + +extension UICollectionViewDiffableDataSource { + + struct ReorderingHandlers { + var canReorderItem: ((Item) -> Bool)? + var willReorder: ((NSDiffableDataSourceTransaction) -> Void)? + var didReorder: ((NSDiffableDataSourceTransaction) -> Void)? + } + + var reorderingHandlers: ReorderingHandlers +} +``` + +* Automatic reordering. +* A struct which contains three optional closures: `canReorderItem`, `willReorder`, and `didReorder`. +* First need to supply a `canReorderItem` closure. +* When the user is done with the reordering interaction, the `didReorder` closure is called. +* Must provide both the `canReorderItem` and `didReorder` closure to enable the reordering feature. + +### [Reordering Transactions](https://developer.apple.com/documentation/uikit/nsdiffabledatasourcetransaction) +A transaction that describes the changes after reordering the items in the view. + +```swift +struct NSDiffableDataSourceTransaction { + var initialSnapshot: NSDiffableDataSourceSnapshot { get } + var finalSnapshot: NSDiffableDataSourceSnapshot { get } + var difference: CollectionDifference { get } + var sectionTransactions: [NSDiffableDataSourceSectionTransaction] { get } +} +``` +* `initialSnapshot` is the state of the Diffable Data Source before the update is applied. +* `finalSnapshot` is the state of the Diffable Data Source after the update is applied. +* Apply the data directly to `difference`, if use a data type such as `Array` for the source of truth. +* `sectionTransactions` provides per-section details about all the sections involved in this reordering update. + +#### [Section Transactions](https://developer.apple.com/documentation/uikit/nsdiffabledatasourcesectiontransaction) +```swift +struct NSDiffableDataSourceSectionTransaction { + var sectionIdentifier: Section { get } + var initialSnapshot: NSDiffableDataSourceSectionSnapshot { get } + var finalSnapshot: NSDiffableDataSourceSectionSnapshot { get } + var difference: CollectionDifference { get } +} +``` +* `sectionIdentifier` for inspecting which section this sectionTransaction has been applied to. + +#### Example +```swift +dataSource.reorderingHandlers.didReorder = { [weak self] transaction in + guard let self = self else { return } + + if let updateBackingStore = self.backingStore.applying(transaction.difference) { + self.backingStore = updatedBackingStore + } +} +``` + +[section_snapshots]: ../../../images/notes/wwdc20/10045/section_snapshots.png \ No newline at end of file diff --git a/content/notes/wwdc20/10097.md b/content/notes/wwdc20/10097.md new file mode 100644 index 00000000..f04b1472 --- /dev/null +++ b/content/notes/wwdc20/10097.md @@ -0,0 +1,101 @@ +--- +contributors: dasauto +--- +# Sample Code +Download the [sample code](https://developer.apple.com/documentation/uikit/views_and_controls/collection_views/implementing_modern_collection_views) to learn more about Modern Collection Views. + +# Modern Collection View APIs Overview +![][modern_collection_view_apis] + +# Diffable Data Source +## Recap + +* Introduced in iOS 13. +* Simplifies UI State. +* Automatic animations. +* More to watch session [220](https://developer.apple.com/videos/play/wwdc2019/220) from WWDC 19: Advances in UI Data Sources. + +## New to iOS 14 +### [Section Snapshots](https://developer.apple.com/documentation/uikit/nsdiffabledatasourcesectionsnapshot) +* It encapsulates the data for a single section in a UICollectionView. +* Allow data sources to be more composable into section-sized chunks of data. (It's able to present same data use different layout in different sections.) +* Allow modeling of hierarchical data, which is needed to support rendering outline-style UIs. + +#### Examples +![][section_snapshots] + +* Top: Horizontally scrolling section. +* Middle: Outline style section. +* Bottom: List section. + +More to watch session [10045](https://developer.apple.com/videos/play/wwdc2020/10045/): Advances in diffable data sources. → [Note](10045) + +# Compositional Layout +## Recap +* Introduced in iOS 13. +* Allow us to build rich, complex layouts by composing smaller, easy-to-reason bits of layout together. +* Describe what you want the layout to look like instead of how the layout ought to work. +* Provide section-specific layouts. +* More to watch session [215](https://developer.apple.com/videos/play/wwdc2019/215) from WWDC 19: Advances in Collection View Layout. + +## New to iOS 14 +### [Lists](https://developer.apple.com/documentation/uikit/uicollectionviewcompositionallayout) +* UITableView like appearance. +* Lists are rich with features like swipe actions and many common cell layouts. +* List is built on top of Compositional Layout. +* New concrete UICollectionViewListCell. +* Header and footer support +* Sidebar appearance. + +#### Examples +Creating a UICollectionViewLayout where every section in the collection view is a list with an inset grouped appearance. + +```swift +let configuration = UICollectionLayoutListConfiguration(appearance: .insetGrouped) +let layout = UICollectionViewCompositionalLayout.list(using: configuration) +``` + +More to watch session [10026](https://developer.apple.com/wwdc20/10026): Lists in UICollectionView. + +# Modern Cells +## [Cell Registrations](https://developer.apple.com/documentation/uikit/uicollectionview/cellregistration) +* A brand new way to configure cells. +* A simple, re-usable way to set up a cell from a view model. +* Eliminate the extra step of registering a cell class or nib to associate it with a re-use identifier. +* Use a generic registration type which incorporates a configuration closure for setting up a new cell from a view model. + +```swift +let reg = UICollectionView.CellRegistration { cell, indexPath, model in + // configure cell content +} + +let dataSource = UICollectionViewDiffableDataSource(collectionView: collectionView) { + collectionView, indexPath, item -> UICollectionViewCell in + return collectionView.dequeueConfiguredReusableCell(using: reg, for: indexPath, item: item) +} +``` + +## [Cell Content Configurations](https://developer.apple.com/documentation/uikit/uilistcontentconfiguration) +* Similar to UITableViewCell types. +* Use with any cell or even a generic UI view. +* Flexible. +* Lightweight. + +```swift +var contentConfiguration = UIListContentConfiguration.cell() +contentConfiguration.image = UIImage(systemNamed:"hammer") +contentConfiguration.text = "Ready. Set. Code" +cell.contentConfiguration = contentConfiguration +``` + +## [Background Configurations](https://developer.apple.com/documentation/uikit/uibackgroundconfiguration) +* Similar to content configurations but applied to any cell's background with the ability to adjust properties such as color, border styles, and more. + +```swift +cell.backgroundConfiguration = UIBackgroundConfiguration.clear() +``` + +More to watch session [10027](https://developer.apple.com/wwdc20/10027): Modern cell configuration. + +[modern_collection_view_apis]: ../../../images/notes/wwdc20/10097/modern_collection_view_apis.png +[section_snapshots]: ../../../images/notes/wwdc20/10097/section_snapshots.png diff --git a/images/notes/wwdc20/10045/section_snapshots.png b/images/notes/wwdc20/10045/section_snapshots.png new file mode 100644 index 00000000..5cbdf89e Binary files /dev/null and b/images/notes/wwdc20/10045/section_snapshots.png differ diff --git a/images/notes/wwdc20/10097/modern_collection_view_apis.png b/images/notes/wwdc20/10097/modern_collection_view_apis.png new file mode 100644 index 00000000..b44c8663 Binary files /dev/null and b/images/notes/wwdc20/10097/modern_collection_view_apis.png differ diff --git a/images/notes/wwdc20/10097/section_snapshots.png b/images/notes/wwdc20/10097/section_snapshots.png new file mode 100644 index 00000000..5cbdf89e Binary files /dev/null and b/images/notes/wwdc20/10097/section_snapshots.png differ