आईओएस 13. बेसिक्स पर कंपोजल लेआउट

नमस्कार,


व्यवहार में, iOS, डेवलपर अक्सर एक सूची के रूप में या एक संग्रह के रूप में, एक नियम के रूप में, बड़ी मात्रा में जानकारी प्रदर्शित करने के कार्य का सामना करता है UITableViewया इसके लिए महान होता है UICollectionViewअक्सर सामना किया गया एक स्क्रीन को साकार करने का कार्य भी है, जो एक सूची और संग्रह का एक संयोजन है।


इस लेख में, हम विचार करेंगे कि इस कार्य को कार्यान्वित करने के लिए iOS 13 कौन सी नई सुविधाएँ लाया है।



परिचय


, , , , AppStore.



?


iOS 13,


  • ,
  • ,
  • ,
  • UIScrollView

.


  • self-sizing
  • iPad iPhone

iOS 12.


Compositional Layout


iOS 13 Apple , — Compositional Layout, 3- — , .


, , , , , , , .



Compositional Layout — , , .




— , , - . , .


— grid-, flow- , .


— , , .


Compositional Layout. 4 :


  • NSCollectionLayoutSize — ;
  • NSCollectionLayoutItem — ;
  • NSCollectionLayoutGroup — , ;
  • NSCollectionLayoutSection — ;
  • UICollectionViewCompositionalLayout — .

UICollectionViewCompositionalLayout.


class UICollectionViewCompositionalLayout : UICollectionViewLayout { ... }

UICollectionViewCompositionalLayout UICollectionViewLayout, UICollectionView.


List Layout


. storyboard-, UIViewController, viewDidLoad() UICollectionView init(frame:, layout:) UICollectionViewCompositionalLayout. , UICollectionViewCompositionalLayout.


, . , , , .



.


    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 configureHierarchy() {
        collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: createLayout())
        // ...
    }

itemSize , , NSCollectionLayoutDimension. .


  • fractionalWidth(_:), , 0 1 , , 0.5 — () ;
  • fractionalHeight(_: ), , 0 1 , , 0.5 — () ;
  • absolute(_: ), , , 44.0;
  • estimated(_:), , .

itemSize widthDimension = .fractionalWidth(1.0), heightDimension = .fractionalHeight(1.0), , . .


, widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(44), , , 44.0.


:


  • horizontal(layoutSize: , subitem: , count: ), , ;
  • horizontal(layoutSize:, subitems: ), , , ;
  • vertical(layoutSize:, subitem:, count:), , ;
  • vertical(layoutSize:, subitems: ), , , ;
  • custom(layoutSize:, itemProvider: ), , .

, .horizontal .vertical , , , .custom , , .


NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item]) , , .


NSCollectionLayoutSection(group: group), . Compositional Layout.


, , . ?


Grid Layout



, ? , , , .


let itemSize = NSCollectionLayoutSize(
            widthDimension: .fractionalWidth(1.0/4.0), // <---
            heightDimension: .fractionalHeight(1.0))

, 4 , .



Two Column Layout


, , , , , widthDimension .



.


    private func createLayout() -> UICollectionViewLayout {
        let spacing: CGFloat = 10
        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) // <---
        group.interItemSpacing = .fixed(spacing)

        let section = NSCollectionLayoutSection(group: group)
        section.contentInsets = .init(top: spacing, leading: spacing, bottom: spacing, trailing: spacing)
        section.interGroupSpacing = spacing

        let layout = UICollectionViewCompositionalLayout(section: section)
        return layout
    }

group.interItemSpacing = .fixed(spacing), section.interGroupSpacing = spacing, contentInset section.contentInsets = .init(top: spacing, leading: spacing, bottom: spacing, trailing: spacing). spacing.


, interItemSpacing , interGroupSpacing, NSCollectionLayoutSpacing.


class NSCollectionLayoutSpacing : NSObject, NSCopying {
    class func fixed(_ fixedSpacing: CGFloat) -> Self // i.e. ==
    class func flexible(_ flexibleSpacing: CGFloat) -> Self // i.e. >=
    // ...
}

  • func fixed(_ fixedSpacing: ), ;
  • func flexible(_ flexibleSpacing:), , , ;

Inset Items Grid Layout


, , ? , , . , 5 , , 1.0/5.0 , . , 1.0/5.0 . , .
, .contentInsets NSCollectionLayoutItem.



.


    private func createLayout() -> UICollectionViewLayout {
        let spacing: CGFloat = 10
        let itemSize = NSCollectionLayoutSize(
            widthDimension: .fractionalWidth(0.2),
            heightDimension: .fractionalHeight(1.0))
        let item = NSCollectionLayoutItem(layoutSize: itemSize)
        item.contentInsets = .init(top: spacing, leading: spacing, bottom: spacing, trailing: spacing)

        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
    }

Distinct Sections Layout


, .


UICollectionViewCompositionalLayout , UICollectionViewCompositionalLayoutSectionProvider.


typealias UICollectionViewCompositionalLayoutSectionProvider = (Int, NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection?

class UICollectionViewCompositionalLayout : UICollectionViewLayout {
   init(section: NSCollectionLayoutSection)
   init(sectionProvider: @escaping UICollectionViewCompositionalLayoutSectionProvider)
   // ...
}

UICollectionViewCompositionalLayoutSectionProvider 2 , , , .


3 , , grid- 3- , grid-, 5- .



.


    enum Section: Int, CaseIterable {
        case list
        case grid3
        case grid5

        var columnCount: Int {
            switch self {
            case .list:
                return 1
            case .grid3:
                return 3
            case .grid5:
                return 5
            }
        }
    }

    private func createLayout() -> UICollectionViewLayout {
        let layout = UICollectionViewCompositionalLayout { (sectionIndex, layoutEnvironment) -> NSCollectionLayoutSection? in

            guard let sectionKind = Section(rawValue: sectionIndex) else { return nil }
            let columns = sectionKind.columnCount

            let itemSize = NSCollectionLayoutSize(
                widthDimension: .fractionalWidth(1.0),
                heightDimension: .fractionalHeight(1.0))
            let item = NSCollectionLayoutItem(layoutSize: itemSize)
            item.contentInsets = .init(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 = .init(top: 20, leading: 20, bottom: 20, trailing: 20)
            return section
        }
        return layout
    }
// ...

Adaptive Sections Layout


, NSCollectionLayoutEnvironment , traitCollection.


protocol NSCollectionLayoutEnvironment : NSObjectProtocol {
    var container: NSCollectionLayoutContainer { get }
    var traitCollection: UITraitCollection { get }
}

ompact size-class , , , , .


traitCollection.verticalSizeClass layoutEnvironment .


container.effectiveContentSize layoutEnvironment .



.



.


    enum Section: Int, CaseIterable {
        case list
        case grid3
        case grid5

        func columnCount(for width: CGFloat) -> Int {
            let wideMode = width > 800
            switch self {
            case .list:
                return wideMode ? 2 : 1
            case .grid3:
                return wideMode ? 6 : 3
            case .grid5:
                return wideMode ? 10 : 5
            }
        }
    }

    private func createLayout() -> UICollectionViewLayout {
        let layout = UICollectionViewCompositionalLayout { (sectionIndex, layoutEnvironment) -> NSCollectionLayoutSection? in

            guard let sectionKind = Section(rawValue: sectionIndex) else { return nil }
            let columns = sectionKind.columnCount(for: layoutEnvironment.container.effectiveContentSize.width)

            let itemSize = NSCollectionLayoutSize(
                widthDimension: .fractionalWidth(1.0),
                heightDimension: .fractionalHeight(1.0))
            let item = NSCollectionLayoutItem(layoutSize: itemSize)
            item.contentInsets = .init(top: 2, leading: 2, bottom: 2, trailing: 2)

            let groupHeight = layoutEnvironment.traitCollection.verticalSizeClass == .compact ?
                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 = .init(top: 20, leading: 20, bottom: 20, trailing: 20)
            return section
        }
        return layout
    }

// ...

Nested Groups


class NSCollectionLayoutGroup : NSCollectionLayoutItem, NSCopying { ... }

NSCollectionLayoutGroup, , NSCollectionLayoutItem, , , .



.


    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 bottomNestedGroup = NSCollectionLayoutGroup.horizontal(
                layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
                                                   heightDimension: .fractionalHeight(0.6)),
                subitems: [leadingItem, trailingGroup])

            let topItem = NSCollectionLayoutItem(
                layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
                                               heightDimension: .fractionalHeight(0.3)))
            topItem.contentInsets = NSDirectionalEdgeInsets(top: 10, leading: 10, bottom: 10, trailing: 10)

            let nestedGroup = NSCollectionLayoutGroup.vertical(
                layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
                                                   heightDimension: .fractionalHeight(0.4)),
                subitems: [topItem, bottomNestedGroup])
            let section = NSCollectionLayoutSection(group: nestedGroup)
            return section

        }
        return layout
    }

Nested Groups Scrolling


? ! , , .


// ...
section.orthogonalScrollingBehavior = .continuous
// ...



iOS 13 UICollectionView, Compositional Layout .
. .


:



All Articles