初探iOS UICollectionView新功能

概述:

在iOS 13贩挣、iOS 14以后揍堰,UICollectionView 進(jìn)行了很多變化。其中最主要的兩點(diǎn)就是:

  1. UICollectionViewCompositionalLayout
    組合布局,一種集合視圖布局,它是可組合的惜论、靈活的和快速的,允許您為內(nèi)容構(gòu)建任何類型的視覺安排止喷。
  2. UICollectionViewDiffableDataSource
    一種特殊類型的數(shù)據(jù)源馆类,它提供了簡單高效地管理集合視圖數(shù)據(jù)和用戶界面更新所需的行為。

一弹谁、UICollectionViewCompositionalLayout介紹

自從iOS 6出現(xiàn)了UICollectionView乾巧,在iOS 13以前我們創(chuàng)建并顯示,是通過UICollectionViewFlowLayout布局做到的预愤。
其中UICollectionViewFlowLayout擁有

@property (nonatomic) CGFloat minimumLineSpacing;
@property (nonatomic) CGFloat minimumInteritemSpacing;
@property (nonatomic) CGSize itemSize;
@property (nonatomic) CGSize estimatedItemSize API_AVAILABLE(ios(8.0)); // defaults to CGSizeZero - setting a non-zero size enables cells that self-size via -preferredLayoutAttributesFittingAttributes:
@property (nonatomic) UICollectionViewScrollDirection scrollDirection; // default is UICollectionViewScrollDirectionVertical
@property (nonatomic) CGSize headerReferenceSize;
@property (nonatomic) CGSize footerReferenceSize;
@property (nonatomic) UIEdgeInsets sectionInset;

等屬性沟于,來控制每一個(gè)item在UICollectionView中的顯示。
到了iOS 13植康,蘋果引入了UICollectionViewCompositionalLayout用來設(shè)置UICollectionView的布局旷太。

總覽

合成布局是一種集合視圖布局。 它的設(shè)計(jì)具有可組合性销睁,靈活性和快速性供璧,可讓您通過將每個(gè)較小的組件組合(或合成)成完整的布局來為內(nèi)容構(gòu)建任何形式的視覺布置。
合成布局由一個(gè)或多個(gè)部分組成冻记,這些部分將布局分解為不同的視覺分組睡毒。 每個(gè)部分都是由各個(gè)項(xiàng)目組成的組,這些項(xiàng)目是要顯示的最小數(shù)據(jù)單元檩赢。 一組人員可以將其項(xiàng)目布置在水平行,垂直列或自定義排列中。
您可以通過以下方式將組件組合在一起:從項(xiàng)目(item)到一個(gè)組(group)贞瞒,從組到一個(gè)節(jié)(section)偶房,最后到完整的布局。


UICollectionViewCompositionalLayout總覽

創(chuàng)建網(wǎng)絡(luò)布局的代碼如下:

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
    }

知識(shí)點(diǎn):1.NSCollectionLayoutSize為:

每個(gè)組件的尺寸(NSCollectionLayoutDimension)的一對(duì)寬军浆、高的尺寸棕洋。集合視圖布局的每個(gè)組件都有一個(gè)明確的大小。

原文:

A size is a pair of dimensions (NSCollectionLayoutDimension): a width dimension and a height dimension. Every component of a collection view layout has an explicit size.

知識(shí)點(diǎn):2.NSCollectionLayoutDimension為:

集合視圖中項(xiàng)目尺寸(寬度或高度)的單個(gè)尺寸乒融。
集合視圖中的每個(gè)項(xiàng)目都有一個(gè)明確的寬度尺寸和高度尺寸掰盘,這兩個(gè)尺寸組合在一起定義了項(xiàng)目的尺寸(NSCollectionLayoutSize)。
您可以使用絕對(duì)值赞季,估計(jì)值或分?jǐn)?shù)值來表示項(xiàng)目的尺寸愧捕。
使用絕對(duì)值來指定確切的尺寸,例如44 x 44點(diǎn)正方形:

let absoluteSize = NSCollectionLayoutSize(widthDimension: .absolute(44),
                                         heightDimension: .absolute(44))

如果內(nèi)容的大小可能在運(yùn)行時(shí)發(fā)生更改(例如申钩,在加載數(shù)據(jù)時(shí)或響應(yīng)系統(tǒng)字體大小更改時(shí))次绘,請(qǐng)使用估計(jì)值。 您提供初始估計(jì)大小撒遣,然后系統(tǒng)會(huì)計(jì)算實(shí)際值邮偎。
(這個(gè)應(yīng)該是為了根據(jù)內(nèi)容自適應(yīng)使用的)

let estimatedSize = NSCollectionLayoutSize(widthDimension: .estimated(200),
                                          heightDimension: .estimated(100))

使用分?jǐn)?shù)值來定義相對(duì)于商品容器尺寸的值。 此選項(xiàng)簡化了寬高比的指定义黎。

//以下項(xiàng)目的寬度和高度都等于其容器(父view)寬度的20%禾进,從而創(chuàng)建一個(gè)隨容器大小變化而增大和縮小的正方形。
let fractionalSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.2),
                                           heightDimension: .fractionalWidth(0.2))
等于其容器寬度的20%正方形的Cell

知識(shí)點(diǎn):3. 使用horizontal(layoutSize:subitem:count:)創(chuàng)建布局

使用count參數(shù)中指定的確切項(xiàng)數(shù)創(chuàng)建一個(gè)組廉涕。這種方法簡化了精確指定一個(gè)組包含多少項(xiàng)的過程泻云。在這種情況下,count參數(shù)優(yōu)先于itemSize火的,并且自動(dòng)計(jì)算項(xiàng)大小以適合指定的項(xiàng)數(shù)壶愤。

let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitem: item, count: 3)
使用count參數(shù)

知識(shí)點(diǎn):4. NSCollectionLayoutItem

集合視圖布局的最基本組成部分

總覽

一項(xiàng)是關(guān)于如何在集合視圖中調(diào)整大小,空間和安排單個(gè)內(nèi)容的藍(lán)圖馏鹤。一個(gè)項(xiàng)目代表在屏幕上呈現(xiàn)的單個(gè)視圖征椒。通常,項(xiàng)目是一個(gè)單元格湃累,但項(xiàng)目可以是補(bǔ)充視圖勃救,例如頁眉,頁腳和其他裝飾治力。
例如蒙秒,在“照片”應(yīng)用中,一個(gè)項(xiàng)目可能代表一張照片宵统。在App Store應(yīng)用程序中晕讲,項(xiàng)目可能是一個(gè)單元格,用于在特色應(yīng)用程序列表中顯示有關(guān)單個(gè)應(yīng)用程序的信息,例如應(yīng)用程序圖標(biāo)瓢省,應(yīng)用程序名稱弄息,標(biāo)語和下載按鈕。
(見上圖UICollectionViewCompositionalLayout總覽)

知識(shí)點(diǎn):5. NSCollectionLayoutGroup

一組項(xiàng)目的容器勤婚,用于沿著路徑布置項(xiàng)目摹量。

總覽

組確定集合視圖中的items如何相對(duì)于彼此進(jìn)行布局÷ǎ可以將items按照行缨称、列或自定義布置到Group中。
一個(gè)組確定有關(guān)如何相互呈現(xiàn)項(xiàng)目的規(guī)則祝迂,但其本身不呈現(xiàn)任何內(nèi)容睦尽。
例如,在“照片”應(yīng)用中液兽,一組項(xiàng)目是一排照片骂删。在App Store應(yīng)用程序中,組可能是垂直列中排列的一列單元格(項(xiàng)目)四啰。
(見上圖UICollectionViewCompositionalLayout總覽)

因?yàn)榻M是NSCollectionLayoutItem的子類宁玫,所以它的行為類似于Item。您可以將一個(gè)組與其他項(xiàng)目和組組合成更復(fù)雜的布局柑晒。


多個(gè)NSCollectionLayoutGroup組合

多個(gè)group組合欧瘪,以上顯示可以用代碼實(shí)現(xiàn)為:

//先定義左邊大的主item,設(shè)置寬度占整個(gè)group的70%匙赞,高度為100%
let leadingItem = NSCollectionLayoutItem(
    layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.7),
                                      heightDimension: .fractionalHeight(1.0)))
leadingItem.contentInsets = NSDirectionalEdgeInsets(top: 10, leading: 10, bottom: 10, trailing: 10)
//再定義右邊兩個(gè)小的為一組佛掖,按照豎排列,2個(gè)一組
//兩個(gè)小的item涌庭,設(shè)置寬度占整個(gè)group的100%芥被,高度為50%
let trailingItem = NSCollectionLayoutItem(
    layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
                                      heightDimension: .fractionalHeight(0.5)))
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)
//再把上面的leadingItem和trailingGroup放到一個(gè)組里
let nestedGroup = NSCollectionLayoutGroup.horizontal(
    layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
                                      heightDimension: .fractionalHeight(0.4)),
    subitems: [leadingItem, trailingGroup])

知識(shí)點(diǎn):6. NSCollectionLayoutSection

一個(gè)將一個(gè)個(gè)Group組合為不同的可視分組的容器。

總覽

集合視圖布局具有一個(gè)或多個(gè)section坐榆。 各section提供了一種將布局分成不同部分的方法拴魄。
每個(gè)section可以具有與集合視圖中其他section相同或不同的布局。 section的布局由用于創(chuàng)建section的組(NSCollectionLayoutGroup)的屬性確定席镀。
例如匹中,在“照片”應(yīng)用中,“年份”頁面中的每個(gè)部分都使用相同的布局豪诲。 在App Store中顶捷,“應(yīng)用程序”頁面顯示具有不同內(nèi)容排列的幾個(gè)部分。
(見上圖UICollectionViewCompositionalLayout總覽)

通過以上1屎篱、2服赎、3葵蒂、4、5重虑、6各部分刹勃,就可以組成一個(gè)UICollectionViewCompositionalLayout了。

let layout = UICollectionViewCompositionalLayout(section: section)
var collectionView: UICollectionView! = nil
collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)

就可以初始化一個(gè)collectionView了嚎尤。
如果擁有多個(gè)section,并且section之間顯示還不一樣伍宦,可以用如下方法實(shí)現(xiàn)

func createLayout() -> UICollectionViewLayout {
        let layout = UICollectionViewCompositionalLayout {
            (sectionIndex: Int, layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? in
            if sectionIndex == 0{
                let section = NSCollectionLayoutSection(group: Group0)
                return section
            } else {
                let section = NSCollectionLayoutSection(group: Group1)
                return section
            }
        }
        return layout
    }

知識(shí)點(diǎn):7. NSCollectionLayoutSupplementaryItem

可以使用NSCollectionLayoutSupplementaryItem給item, group, section來添加角標(biāo)等信息芽死。

用于向集合視圖中的項(xiàng)目添加額外的視覺裝飾(例如徽章或框架)的對(duì)象。



例子:定義UICollectionViewCompositionalLayout時(shí)次洼,在每個(gè)item上加角標(biāo)

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: "badge-element-kind",
    containerAnchor: badgeAnchor)
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.2),
                                     heightDimension: .fractionalHeight(1.0))
let item = NSCollectionLayoutItem(layoutSize: itemSize, supplementaryItems: [badge])

給UICollectionViewDiffableDataSource添加屬性

let supplementaryRegistration = UICollectionView.SupplementaryRegistration<BadgeSupplementaryView>(elementKind: "badge-element-kind") {
            (badgeView, string, indexPath) in
            
            let hasBadgeCount = (indexPath.row%2) > 0//奇數(shù)個(gè)時(shí)顯示角標(biāo)
            // Set the badge count as its label (and hide the view if the badge count is zero).
            badgeView.label.text = "\(indexPath.row)"
            badgeView.isHidden = !hasBadgeCount
        }
        dataSource.supplementaryViewProvider = {
            return self.collectionView.dequeueConfiguredReusableSupplementary(using: supplementaryRegistration, for: $2)
        }

得到結(jié)果為:


NSCollectionLayoutSupplementaryItem角標(biāo)

知識(shí)點(diǎn):8. 用UICollectionView實(shí)現(xiàn)TableView樣式

在 iOS14 中,用 CollectionView 實(shí)現(xiàn)一個(gè) TableView 樣式的列表非常簡單关贵。

func createLayout() -> UICollectionViewLayout {
        let configuration = UICollectionLayoutListConfiguration(appearance: .insetGrouped)
        return UICollectionViewCompositionalLayout.list(using: configuration)
    }

其中insetGrouped為樣式。還有plain卖毁、grouped揖曾、insetGrouped、sidebar亥啦、sidebarPlain等樣式炭剪。

二、注冊(cè)初始化Cell

iOS 14提供了一個(gè)新方法:UICollectionView.CellRegistration用來注冊(cè)Cell

let cellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, Int> { cell, indexPath, item in
    var contentConfiguration = cell.defaultContentConfiguration()
    contentConfiguration.text = "\(item)"
    contentConfiguration.textProperties.color = .lightGray
    cell.contentConfiguration = contentConfiguration
}

三翔脱、UICollectionViewDiffableDataSource

這是iOS 13新提出的方法奴拦。

用于管理數(shù)據(jù)和為集合視圖提供單元格的對(duì)象。

概述

diffable數(shù)據(jù)源對(duì)象是一種特殊類型的數(shù)據(jù)源届吁,與collection view一起工作错妖。它提供了以簡單、高效的方式管理collection view數(shù)據(jù)和UI更新所需的行為疚沐。它還符合UICollectionViewDataSource協(xié)議暂氯,并為該協(xié)議的所有方法提供實(shí)現(xiàn)。
要用數(shù)據(jù)填充collection view亮蛔,請(qǐng)執(zhí)行以下操作:

  1. 將可擴(kuò)散數(shù)據(jù)源連接到collection view痴施。
  2. 實(shí)現(xiàn)單元提供程序以配置collection view的cells 。
  3. 生成數(shù)據(jù)的當(dāng)前狀態(tài)尔邓。
  4. 在UI中顯示數(shù)據(jù)晾剖。
    要將可擴(kuò)散數(shù)據(jù)源連接到集合視圖,可以使用其init(collectionView:cellProvider:)與要在view中傳遞數(shù)據(jù)的初始值設(shè)定項(xiàng)相關(guān)聯(lián)梯嗽。您還將傳入一個(gè)cell提供程序齿尽,在該程序中配置每個(gè)單元格以確定如何在UI中顯示數(shù)據(jù)。

知識(shí)點(diǎn):1. 將Diffable Data Source連接到collection view

dataSource = UICollectionViewDiffableDataSource.init(collectionView: collectionView, cellProvider: {
    (collectionView: UICollectionView, indexPath: IndexPath, identifier: Int) -> UICollectionViewCell? in
    return collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: identifier)
})

知識(shí)點(diǎn):2. NSDiffableDataSourceSnapshot

然后灯节,生成數(shù)據(jù)的當(dāng)前狀態(tài)循头,并通過構(gòu)造和應(yīng)用快照在UI中顯示數(shù)據(jù):

視圖中數(shù)據(jù)在特定時(shí)間點(diǎn)的狀態(tài)表示绵估。

概述

Diffable data sources使用快照為collection views 和 table views提供數(shù)據(jù)。通過快照卡骂,可以設(shè)置在視圖中顯示的數(shù)據(jù)的初始狀態(tài)国裳,然后更新該數(shù)據(jù)。
快照中的數(shù)據(jù)由要顯示的sections和items組成全跨,按要顯示的特定順序排列缝左。您可以通過添加adding、刪除deleting或移動(dòng)moving sections和items來配置要顯示的內(nèi)容浓若。

重要

每個(gè)sections和items都必須具有符合哈希協(xié)議的唯一標(biāo)識(shí)符渺杉。

要使用快照在視圖中顯示數(shù)據(jù),請(qǐng)執(zhí)行以下操作:
創(chuàng)建快照并用要顯示的數(shù)據(jù)的狀態(tài)填充它挪钓。
應(yīng)用快照以反映UI中的更改是越。
您可以通過以下方式之一創(chuàng)建和配置快照:
創(chuàng)建一個(gè)空快照,然后向其附加節(jié)和項(xiàng)碌上。
通過調(diào)用diffable數(shù)據(jù)源的snapshot()方法獲取當(dāng)前快照倚评,然后修改該快照以反映要顯示的數(shù)據(jù)的新狀態(tài)。

var snapshot = NSDiffableDataSourceSnapshot<Section, Int>()
snapshot.appendSections([.main])
snapshot.appendItems(Array(0..<30))
dataSource.apply(snapshot, animatingDifferences: false)

其中Section具有符合哈希協(xié)議的唯一標(biāo)識(shí)符

enum Section {
    case main
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末馏予,一起剝皮案震驚了整個(gè)濱河市天梧,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌霞丧,老刑警劉巖腿倚,帶你破解...
    沈念sama閱讀 206,602評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異蚯妇,居然都是意外死亡敷燎,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門箩言,熙熙樓的掌柜王于貴愁眉苦臉地迎上來硬贯,“玉大人,你說我怎么就攤上這事陨收》贡” “怎么了?”我有些...
    開封第一講書人閱讀 152,878評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵务漩,是天一觀的道長拄衰。 經(jīng)常有香客問我,道長饵骨,這世上最難降的妖魔是什么翘悉? 我笑而不...
    開封第一講書人閱讀 55,306評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮居触,結(jié)果婚禮上妖混,老公的妹妹穿的比我還像新娘老赤。我一直安慰自己,他們只是感情好制市,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評(píng)論 5 373
  • 文/花漫 我一把揭開白布抬旺。 她就那樣靜靜地躺著,像睡著了一般祥楣。 火紅的嫁衣襯著肌膚如雪开财。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,071評(píng)論 1 285
  • 那天误褪,我揣著相機(jī)與錄音床未,去河邊找鬼。 笑死振坚,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的斋扰。 我是一名探鬼主播渡八,決...
    沈念sama閱讀 38,382評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼传货!你這毒婦竟也來了屎鳍?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,006評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤问裕,失蹤者是張志新(化名)和其女友劉穎逮壁,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體粮宛,經(jīng)...
    沈念sama閱讀 43,512評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡窥淆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了巍杈。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片忧饭。...
    茶點(diǎn)故事閱讀 38,094評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖筷畦,靈堂內(nèi)的尸體忽然破棺而出词裤,到底是詐尸還是另有隱情,我是刑警寧澤鳖宾,帶...
    沈念sama閱讀 33,732評(píng)論 4 323
  • 正文 年R本政府宣布吼砂,位于F島的核電站,受9級(jí)特大地震影響鼎文,放射性物質(zhì)發(fā)生泄漏渔肩。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評(píng)論 3 307
  • 文/蒙蒙 一拇惋、第九天 我趴在偏房一處隱蔽的房頂上張望赖瞒。 院中可真熱鬧女揭,春花似錦、人聲如沸栏饮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽袍嬉。三九已至境蔼,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間伺通,已是汗流浹背箍土。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評(píng)論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留罐监,地道東北人吴藻。 一個(gè)月前我還...
    沈念sama閱讀 45,536評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像弓柱,于是被迫代替她去往敵國和親沟堡。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容