Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Backporting Collection View Compositional Layouts

Backporting Collection View Compositional Layouts

What is Collection View Compositional Layouts?
What problem does it solve?
Anatomy: Compositional Layouts
Backporting Collection View Compositional Layouts

- iPlayground 2019 -

Kishikawa Katsumi

September 21, 2019
Tweet

More Decks by Kishikawa Katsumi

Other Decks in Programming

Transcript

  1. Agenda • What is Collection View Compositional Layouts? • What

    problem does it solve? • Anatomy: Compositional Layouts • Backporting Collection View Compositional Layouts
  2. What is Collection View Compositional Layouts? • New API introduced

    by iOS 13 • Extremely easy to build custom complex collection view layouts • Powerful features to beat complex layouts for modern apps
  3. Modern App UI is Complicated! • Various rich contents
 must

    be displayed • Various sizes of content are
 on a scroll view • Nested scrolling
  4. How to make it? • Collection View or
 Stack View

    with Scroll View? • Collection View on Collection View • Collection View Custom Layouts
  5. Why Difficult to Build Custom Collection View Layouts? • Implement

    everything yourself • I don't know where to start • Error prone • Too flexible, overkill
  6. UICollectionViewLayout class UICollectionViewLayout { class var layoutAttributesClass: AnyClass class var

    invalidationContextClass: AnyClass func prepare() func layoutAttributesForElements(in rect: CGRect) func layoutAttributesForItem(at indexPath: IndexPath) func layoutAttributesForSupplementaryView(ofKind: String, at: IndexPath) func layoutAttributesForDecorationView(ofKind: String, at: IndexPath) func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) func invalidationContext(forBoundsChange newBounds: CGRect) func shouldInvalidateLayout(forPreferredLayoutAttributes:, withOriginalAttributes:) func invalidationContext(forPreferredLayoutAttributes:, withOriginalAttributes:) func targetContentOffset(forProposedContentOffset: CGPoint, withScrollingVelocity: CGPoint) func targetContentOffset(forProposedContentOffset: CGPoint) var collectionViewContentSize: CGSize ...
  7. Easy Simple Complex Collection View on Collection View Custom Layouts

    Hard Flow Layout Implementation Layout Layout
  8. Easy Simple Complex Collection View on Collection View Custom Layouts

    Hard Flow Layout Compositional Layouts Implementation Layout Layout
  9. let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .fractionalHeight(1)) let item =

    NSCollectionLayoutItem(layoutSize: itemSize) let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .absolute(50)) let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item]) let section = NSCollectionLayoutSection(group: group)
  10. let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .fractionalHeight(1)) let item =

    NSCollectionLayoutItem(layoutSize: itemSize) let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .absolute(50)) let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item]) let section = NSCollectionLayoutSection(group: group)
  11. let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .fractionalHeight(1)) let item =

    NSCollectionLayoutItem(layoutSize: itemSize) let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .absolute(50)) let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item]) let section = NSCollectionLayoutSection(group: group)
  12. let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .fractionalHeight(1)) let item =

    NSCollectionLayoutItem(layoutSize: itemSize) let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .absolute(50)) let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item]) let section = NSCollectionLayoutSection(group: group)
  13. let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .fractionalHeight(1)) let item =

    NSCollectionLayoutItem(layoutSize: itemSize) let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .absolute(50)) let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item]) let section = NSCollectionLayoutSection(group: group)
  14. let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .fractionalHeight(1)) let item =

    NSCollectionLayoutItem(layoutSize: itemSize) let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .absolute(50)) let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item]) let section = NSCollectionLayoutSection(group: group)
  15. let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .fractionalHeight(1)) let item =

    NSCollectionLayoutItem(layoutSize: itemSize) let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.92), heightDimension: .fractionalHeight(0.4)) let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item]) let section = NSCollectionLayoutSection(group: group)
  16. let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .fractionalHeight(1)) let item =

    NSCollectionLayoutItem(layoutSize: itemSize) let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.92), heightDimension: .fractionalHeight(0.3)) let group = NSCollectionLayoutGroup.vertical(layoutSize: groupSize, subitem: item, count: 3) let section = NSCollectionLayoutSection(group: group)
  17. let layout = UICollectionViewCompositionalLayout { (sectionIndex, environment) -> NSCollectionLayoutSection? in

    switch sectionIndex { case 0: ... return section case 1: ... return section ... } } Compose Them into Layout
  18. ... let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.92), heightDimension: .fractionalHeight(0.4)) let group

    = NSCollectionLayoutGroup.vertical(layoutSize: groupSize, subitems: [itemGroup]) let section = NSCollectionLayoutSection(group: group) section.orthogonalScrollingBehavior = .groupPagingCentered
  19. Orthogonal Scrolling Behavior ... let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.92), heightDimension:

    .fractionalHeight(0.4)) let group = NSCollectionLayoutGroup.vertical(layoutSize: groupSize, subitems: [itemGroup]) let section = NSCollectionLayoutSection(group: group) section.orthogonalScrollingBehavior = .groupPagingCentered
  20. Under development ✅ Spacing ✅ Nested Groups ✅ Supplemental Views

    (e.g. Section Header/Footers) ✅ Pinned Section Header/Footers ✅ Orthogonal Scrolling Behavior ✅ Estimated Size (Autosizing) ✅ Custom Group Item (Absolute Positions) ✅ Drop-in replacement ❌ RTL Support
  21. Drop-in Replacement - (instancetype)initWithSection:(IBPNSCollectionLayoutSection *)section { if (@available(iOS 13, *))

    { return [[NSClassFromString(@"UICollectionViewCompositionalLayout") alloc] initWithSection:section]; } else { IBPUICollectionViewCompositionalLayoutConfiguration *configuration = [IBPUICollectionViewCompositionalLayoutConfiguration defaultConfiguration]; return [self initWithSection:section configuration:configuration]; } }
  22. UICollectionViewLayout class UICollectionViewLayout { ... func prepare() func layoutAttributesForElements(in rect:

    CGRect) -> [UICollecti func layoutAttributesForItem(at indexPath: IndexPath) -> UIColle func layoutAttributesForSupplementaryView(ofKind elementKind: St func layoutAttributesForDecorationView(ofKind elementKind: Strin func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) - ... var collectionViewContentSize: CGSize { get } ...
  23. UICollectionViewLayout class UICollectionViewLayout { ... func prepare() func layoutAttributesForElements(in rect:

    CGRect) -> [UICollecti func layoutAttributesForItem(at indexPath: IndexPath) -> UIColle func layoutAttributesForSupplementaryView(ofKind elementKind: St func layoutAttributesForDecorationView(ofKind elementKind: Strin func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) - ... var collectionViewContentSize: CGSize { get } ...
  24. UICollectionViewLayout class UICollectionViewLayout { ... func prepare() func layoutAttributesForElements(in rect:

    CGRect) -> [UICollecti func layoutAttributesForItem(at indexPath: IndexPath) -> UIColle func layoutAttributesForSupplementaryView(ofKind elementKind: St func layoutAttributesForDecorationView(ofKind elementKind: Strin func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) - ... var collectionViewContentSize: CGSize { get } ...
  25. UICollectionViewLayout class UICollectionViewLayout { ... func prepare() func layoutAttributesForElements(in rect:

    CGRect) -> [UICollecti func layoutAttributesForItem(at indexPath: IndexPath) -> UIColle func layoutAttributesForSupplementaryView(ofKind elementKind: St func layoutAttributesForDecorationView(ofKind elementKind: Strin func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) - ... var collectionViewContentSize: CGSize { get } ...
  26. Wrap up • Collection View Compositional Layouts is incredible! •

    No need to implement collection view layout subclass • Like just editing configurations • Keep your code simple regardless layout become complex • You can use it now! (without iOS 13)
  27. 2019-09-20 07:14:13.535020+0900 ... [29591:20271214] [CompositionalLayout] Attempting to add contentInsets to

    an item's dimension along an estimated axis. This layout axis insets will be ignored (however, any non-estimated axis insets will be applied). Please consider using the item's edgeSpacing or the containing group's interItemSpacing instead.
  28. References • Advances in Collection View Layout
 https://developer.apple.com/videos/play/wwdc2019/215/ • All

    you need to know about UICollectionViewCompositionalLayout
 https://medium.com/flawless-app-stories/all-what-you-need-to-know-about- uicollectionviewcompositionallayout-f3b2f590bdbe • Using CollectionView Compositional Layouts in Swift 5
 https://dev.to/kevinmaarek/using-collectionview-compositional-layouts-in-swift-5-1nan • Move your cells left to right, up and down on iOS 13 — Part 1
 https://medium.com/shopback-engineering/move-your-cells-left-to-right-up-and-down-on- ios-13-part-1-1a5e010f48f9