WWDC2016 Session筆記 - iOS 10 UICollectionView新特性

前言

關(guān)于 iOS 10 UICollectionView的新特性们陆,主要還是體現(xiàn)在如下3個(gè)方面

  1. 順滑的滑動(dòng)體驗(yàn)
    現(xiàn)在基本上人人都離不開手機(jī),手機(jī)的app也每天都有人在用。一個(gè)app的好壞由它的用戶體驗(yàn)決定。在可以滑動(dòng)的視圖里面亲铡,必須要更加絲滑柔順才能獲得用戶的青睞更米。這些UICollectionView的新特性可以讓你們的app比原來更加順滑牛郑,而且這些特性只需要你加入少量的代碼即可達(dá)到目的毅访。
  2. 針對(duì)self-sizing的改進(jìn)
    self-sizing的API在iOS8的時(shí)候被引進(jìn)攘残,iOS10中加入更多特性使cell更加容易去適配蚜枢。
  3. Interactive reordering重排
    這個(gè)功能在iOS9的時(shí)候介紹過了记餐,蘋果在iOS 10的API里面大大增強(qiáng)了這一功能牌捷。

目錄

  • 1.UICollectionViewCell順滑的滑動(dòng)體驗(yàn)
  • 2.UICollectionViewCell的Pre-Fetching預(yù)加載
  • 3.UITableViewCell的Pre-Fetching預(yù)加載
  • 4.針對(duì)self-sizing的改進(jìn)
  • 5.Interactive Reordering
  • 6.UIRefreshControl

一. UICollectionViewCell順滑的滑動(dòng)體驗(yàn)

眾所周知好啰,iOS設(shè)備已良好的用戶體驗(yàn)贏得了廣大的用戶群洲守。iOS系統(tǒng)在用戶點(diǎn)擊屏幕會(huì)立即做出響應(yīng)疑务。而且很大一部分的操作是來自于用戶的滑動(dòng)操作。所以滑動(dòng)的順滑是使用戶沉浸在app中享受的必要條件岖沛。接下來我們就談?wù)刬OS 10 中增加了那些新特性暑始。

我們先來看一下之前 UICollectionView 的體驗(yàn),假設(shè)我們每個(gè)cell都是簡(jiǎn)單的藍(lán)色婴削,實(shí)際開發(fā)app中廊镜,cell會(huì)比這復(fù)雜很多。 我們先生成100個(gè)cell唉俗。當(dāng)用戶滑動(dòng)不是很快的時(shí)候嗤朴,還感覺不出來卡頓,當(dāng)用戶大幅度滑動(dòng)虫溜,整個(gè)UICollectionView的卡頓就很明顯了雹姊。如果整個(gè)cell的DataSource又是從網(wǎng)絡(luò)加載的,那就更加卡頓了衡楞。效果如下圖吱雏。

如果這種app上架,用戶使用過后,很可能就直接給1星評(píng)價(jià)了歧杏。但是為什么會(huì)造成這種問題呢镰惦?我們來分析一下,我們模擬一下系統(tǒng)如何處理重用機(jī)制的犬绒,效果如下圖

在上圖中旺入,我們可以看出,當(dāng)cell準(zhǔn)備加載進(jìn)屏幕的時(shí)候凯力,整個(gè)cell都已經(jīng)加載完成茵瘾,等待在屏幕外面了。而且更重要的是咐鹤,在屏幕外面等待加載的cell是整整一行拗秘!這一行的cell都已經(jīng)加載完數(shù)據(jù)。這是UICollectionView在用戶大幅度滑動(dòng)時(shí)卡頓的根本原因慷暂。用專業(yè)的術(shù)語來說聘殖,掉幀。

接下來我們就來詳細(xì)的說說掉幀的問題行瑞。

當(dāng)今的用戶是很挑剔的,用戶需要一個(gè)很順滑的體驗(yàn)餐禁,只要有一點(diǎn)卡頓血久,很可能一言不合就卸載app了。要想用戶感覺不到卡頓帮非,那么我們的app必須幀率達(dá)到60幀/秒氧吐。用數(shù)學(xué)換算一下就是每幀16毫秒就必須刷新一次。

我們用圖標(biāo)來分析一下掉幀的問題末盔。下面會(huì)出現(xiàn)2種不同的幀筑舅。

第一種情況,下圖是當(dāng)用戶輕微的上下小幅度滑動(dòng)陨舱。這個(gè)時(shí)候每個(gè)cell的加載壓力都不大翠拣,iOS針對(duì)這種情況,已經(jīng)做了很好的優(yōu)化了游盲,所以用戶感覺不到任何卡頓误墓。這種情況是不會(huì)掉幀,用戶也希望能使用如此順滑的app益缎。

第二種情況谜慌,當(dāng)用戶大幅度滑動(dòng),每個(gè)cell加載的壓力很大莺奔,也許需要網(wǎng)絡(luò)請(qǐng)求欣范,也許需要讀取數(shù)據(jù)庫,而且每次都加載一行cell出來,這樣每個(gè)cell的加載時(shí)間都增加了恼琼,加載一行的總時(shí)間也就大大增加了杖刷,如下圖所示。這樣驳癌,不僅僅當(dāng)前幀在加載cell滑燃,總的時(shí)間還會(huì)擠壓到下一幀的時(shí)間里面去。這種情況下颓鲜,用戶就感覺到了卡頓了表窘。

我們換種方式在說明一下2種情況下掉幀的情況。我們用下圖的標(biāo)準(zhǔn)來衡量一下上面2種情況甜滨。下圖分為2部分乐严,上面紅色的區(qū)域,就是表示掉幀的區(qū)域衣摩,因?yàn)楦哂?6ms昂验。紅色和綠色區(qū)域的分界線就在16ms處。y軸我們表示的是CPU在主線程中花費(fèi)的時(shí)間艾扮。x軸表示的是在用戶滑動(dòng)中發(fā)生的刷新事件既琴。

針對(duì)上述掉幀的情況,繪制出實(shí)驗(yàn)數(shù)據(jù)泡嘴,如下圖甫恩。值得我們關(guān)注的是,曲線是很曲折的酌予,非常的不平滑磺箕。當(dāng)用戶大幅度滑動(dòng)的時(shí)候,峰值超過了16ms抛虫,當(dāng)用戶慢速滑動(dòng)的時(shí)候松靡,幀率又能保持在比較順滑的區(qū)域。處于綠色區(qū)域內(nèi)的cell加載壓力都是很小的建椰。這就是時(shí)而掉幀時(shí)而順滑的場(chǎng)景雕欺。這種場(chǎng)景下,用戶體驗(yàn)是很糟糕的广凸。


那怎么解決這么問題的呢阅茶?我們來看下圖:


上圖中的曲線我們看著就很平緩了,而且這種情況也不會(huì)出現(xiàn)掉幀的情況了谅海,每個(gè)滑動(dòng)中的時(shí)間都能達(dá)到60幀了脸哀。這是怎樣做到的呢?因?yàn)榘衙總€(gè)cell的加載事件都平分了扭吁,每個(gè)cell不會(huì)再出現(xiàn)很忙和很閑的兩個(gè)極端撞蜂。這樣我們就取消了之前的波峰和波谷盲镶。從而讓該曲線達(dá)到近乎水平的直線。

如何讓每個(gè)cell都分?jǐn)偧虞d任務(wù)的壓力蝌诡?這就要談到新的cell的生命周期了溉贿。

先來看看老的 UICollectionViewCell的聲明周期。當(dāng)用戶滑動(dòng)屏幕浦旱,屏幕外有一個(gè)cell準(zhǔn)備加載顯示進(jìn)來宇色。

這個(gè)時(shí)候我們把這個(gè)cell從reuse隊(duì)列里面拿出來,然后調(diào)用prepareForReuse方法颁湖。這個(gè)方法就給了cell時(shí)間宣蠕,用來重置cell,重置狀態(tài)甥捺,刷新cell抢蚀,加載新的數(shù)據(jù)。

再滑動(dòng)镰禾,我們就會(huì)調(diào)用cellForItemAtIndexPath方法了皿曲。這個(gè)方法里面就是我們開發(fā)者自定義的填充cell的方式了。這里會(huì)填充data model吴侦,然后賦值給cell屋休,再把cell返回給iOS系統(tǒng)。


當(dāng)cell馬上要進(jìn)入屏幕的時(shí)候妈倔,就會(huì)調(diào)用willDisplayCell的方法博投。這個(gè)方法給了我們app最后一次機(jī)會(huì),為cell進(jìn)入屏幕做最后的準(zhǔn)備工作盯蝴。執(zhí)行完willDisplayCell之后,cell就進(jìn)入屏幕了听怕。


當(dāng)cell完全離開屏幕之后捧挺,就會(huì)調(diào)用didEndDisplayingCell方法。以上就是在iOS10之前的整個(gè)UICollectionViewCell的生命周期尿瞭。

接下來我們就來看看iOS 10的UICollectionViewCell生命周期是怎么樣的闽烙。

這里還是和iOS9一樣的,當(dāng)用戶滑動(dòng)UICollectionView的時(shí)候声搁,需要一個(gè)cell黑竞,我們就從reuse隊(duì)列里面拿出一個(gè)cell,并調(diào)用prepareForReuse方法疏旨。注意調(diào)用這個(gè)方法的時(shí)間很魂,當(dāng)cell還沒有進(jìn)入屏幕的時(shí)候,就已經(jīng)提前調(diào)用這個(gè)方法了檐涝。注意對(duì)比和iOS 9的區(qū)別遏匆,iOS 9 是在cell上邊緣馬上進(jìn)入屏幕的時(shí)候才調(diào)用方法法挨,而這里,cell整個(gè)生命周期都被提前了幅聘,提前到cell還在設(shè)備外面的時(shí)候凡纳。

這里還是和之前一樣,在cellForItemAtIndexPath中創(chuàng)建cell帝蒿,填充數(shù)據(jù)荐糜,刷新狀態(tài)等等操作。注意葛超,這里生命周期也比iOS 9提前了暴氏。

用戶繼續(xù)滑動(dòng),這個(gè)時(shí)候就有不同了巩掺!

這個(gè)時(shí)候我們并不去調(diào)用willDisplayCell方法了偏序!這里遵循的原則是,何時(shí)去顯示胖替,何時(shí)再去調(diào)用willDisplayCell研儒。


當(dāng)cell要馬上就需要顯示的時(shí)候,我們?cè)僬{(diào)用willDisplayCell方法独令。


當(dāng)整個(gè)cell要從UICollectionView的可見區(qū)域消失的時(shí)候端朵,這個(gè)時(shí)候會(huì)調(diào)用didEndDisplayingCell方法。接下來發(fā)生的事情和iOS9一樣燃箭,cell會(huì)進(jìn)入重用隊(duì)列中冲呢。

如果用戶想要顯示某個(gè)cell,在iOS 9 當(dāng)中招狸,cell只能從重用隊(duì)列里面取出敬拓,再次走一遍生命周期。并調(diào)用cellForItemAtIndexPath去創(chuàng)建或者生成一個(gè)cell裙戏。

在iOS 10 當(dāng)中乘凸,系統(tǒng)會(huì)把cell保持一段時(shí)間。在iOS中累榜,如果用戶把cell滑出屏幕后营勤,如果突然又想回來,這個(gè)時(shí)候cell并不需要再走一段的生命周期了壹罚。只需要直接調(diào)用willDisplayCell就可以了葛作。cell就又會(huì)重新出現(xiàn)在屏幕中。這就是iOS 10 的整個(gè)UICollectionView的生命周期猖凛。

上面說的iOS 10里面的場(chǎng)景同樣適用于多列的情況赂蠢。 這時(shí)我們每次只加載一個(gè)cell,而不是每次加載一行的cell形病。當(dāng)?shù)谝粋€(gè)cell準(zhǔn)備好之后再叫第二個(gè)cell準(zhǔn)備客年。當(dāng)2個(gè)cell都準(zhǔn)備好了之后霞幅,接著我們?cè)僬{(diào)用willDisplayCell給每個(gè)cell,發(fā)送完這個(gè)消息之后量瓜,cell就會(huì)出現(xiàn)在屏幕上了司恳。

這雖然看起來是一個(gè)很小的改動(dòng),但是這小小的改動(dòng)就提升了很多的用戶體驗(yàn)绍傲!

讓我們來看看上述的改動(dòng)對(duì)滑動(dòng)的影響

滑動(dòng)比iOS 9流程很多扔傅,這里可以看到整個(gè)過程都很平緩,不卡頓烫饼。

還是和iOS 9一樣猎塞,我們來模擬一下系統(tǒng)是如何加載cell的情況。

我們可以很明顯的看到杠纵,iOS 系統(tǒng)是一個(gè)個(gè)的加載cell的荠耽,一個(gè)cell加載完之后再去加載下一個(gè)cell。這里和iOS 9 的有很大的不同比藻,iOS 9是加載整整一行的cell铝量。

這是因?yàn)槲覀冇昧诵碌?UICollectionViewCell的生命周期。整個(gè)app完全沒有加一行代碼∫祝現(xiàn)在iOS 10是絲滑的滑動(dòng)體驗(yàn)實(shí)在是太棒了B丁!

二. UICollectionViewCell的Pre-Fetching預(yù)加載

當(dāng)我們編譯iOS 10的app的時(shí)候务蝠,這個(gè)Pre-Fetching默認(rèn)是enable的拍谐。當(dāng)然,如果有一些原因?qū)е履惚仨氂玫絠OS 10之前老的生命周期馏段,你只需要給collectionView加入新的isPrefetchingEnabled屬性即可轩拨。如果你不想用到Pre-Fetching,那么把這個(gè)屬性變成false即可院喜。


@property (nonatomic, getter=isPrefetchingEnabled) BOOL prefetchingEnabled NS_AVAILABLE_IOS(10_0);

[collectionView setPrefetchingEnabled:NO];

為了最佳實(shí)踐一下這個(gè)新特性气嫁。我們先改變一下我們加載cell的方式。我們把很重的讀取數(shù)據(jù)的操作够坐,所有內(nèi)容的創(chuàng)建都放到cellForItemAtIndexPath方法里面去完成。保證我們?cè)趙illDisplayCell 和 didEndDisplayCell這兩個(gè)方法里面基本不做其他事情崖面。最后元咙,需要注意的是cellForItemAtIndexPath生成的某些cell,可能永遠(yuǎn)都不會(huì)被展示在屏幕上巫员,有這樣一種情況庶香,當(dāng)cell將要展示在屏幕上的時(shí)候,用戶突然滑動(dòng)離開了這個(gè)界面简识。

如果這個(gè)時(shí)候當(dāng)你用iOS 10編譯出你的app赶掖,那么非常順滑的用戶體驗(yàn)就會(huì)自動(dòng)的優(yōu)化出來感猛。

UICollectionView的流暢的滑動(dòng)解決了,那么在UICollectionViewCell在加載的時(shí)候所花費(fèi)的時(shí)間奢赂,怎么解決呢陪白??

UICollectionViewCell加載的時(shí)間取決于DataModel膳灶。DataModel很可能會(huì)去加載圖片咱士,來自于網(wǎng)絡(luò)或者來自于本地的數(shù)據(jù)庫。這些操作大多數(shù)都是異步的操作轧钓。為了使data加載更快序厉,iOS 10引入了新的API來解決這個(gè)問題。

UICollectionView有2個(gè)“小伙伴”毕箍,那就是data source和delegate弛房。在iOS 10中,將會(huì)迎來第3個(gè)“小伙伴”而柑。這個(gè)“小伙伴”叫prefetchDataSource文捶。

protocol UICollectionViewDataSourcePrefetching {
    func collectionView(_ collectionView: UICollectionView,
                        prefetchItemsAt indexPaths: [NSIndexPath])
    optional func collectionView(_ collectionView: UICollectionView,
                                 cancelPrefetchingForItemsAt indexPaths: [NSIndexPath])
}
class UICollectionView : UIScrollView {
    weak var prefetchDataSource: UICollectionViewDataSourcePrefetching?
    var isPrefetchingEnabled: Bool
}

這個(gè)協(xié)議里面只有一個(gè)必須要實(shí)現(xiàn)的方法——ColletionView prefetchItemsAt indexPaths。這個(gè)方法會(huì)在prefetchDataSource里面被調(diào)用牺堰,用來給你異步的預(yù)加載數(shù)據(jù)的拄轻。indexPaths數(shù)組是有序的,就是接下來item接收數(shù)據(jù)的順序伟葫,讓我們model異步處理數(shù)據(jù)更加方便恨搓。

在這個(gè)協(xié)議里面還有第二個(gè)方法CollectionView cancelPrefetcingForItemsAt indexPaths,不過這個(gè)方法是optional的筏养。我們可以利用這個(gè)方法來處理在滑動(dòng)中取消或者降低提前加載數(shù)據(jù)的優(yōu)先級(jí)斧抱。

值得說明的是,新增加的這個(gè)“小伙伴”prefetchDataSource并不能代替原來的讀取數(shù)據(jù)的方法渐溶,這個(gè)預(yù)加載僅僅只是輔助加載數(shù)據(jù)辉浦,并不能
刪除原來我們讀取數(shù)據(jù)的方法。

至此茎辐,我們來看看從文章開始到現(xiàn)在宪郊,UICollectionView的性能提升了多少。我們還是用掉幀的方法來看看UICollectionView的性能拖陆。

上圖是iOS 9 UICollectionView的性能弛槐,很明顯的看見,波峰波谷很明顯依啰,并且還掉了8幀乎串,有明顯的卡頓現(xiàn)象。

上圖是iOS 10 UICollectionView的性能速警,我們可以很明顯的看到叹誉,經(jīng)過iOS 10的優(yōu)化鸯两,整個(gè)曲線很明顯平緩了一些,沒有極端的波峰掉幀現(xiàn)象长豁。但是依舊存在少量的波峰快到16ms分界線了钧唐。

上圖是iOS 10 + Pre-Fetching API 之后的性能,已經(jīng)優(yōu)化的效果很明顯了蕉斜!整條曲線基本都水平了逾柿。近乎完美。但是還是能發(fā)現(xiàn)有個(gè)別波峰特別高宅此。波峰特別高的地方就是那個(gè)cell加載壓力大机错,時(shí)間花的比較長(zhǎng)導(dǎo)致的。接下來我們繼續(xù)優(yōu)化父腕!

先來總結(jié)一下使用Pre-Fetching API需要注意的地方弱匪。

  1. 在我們使用Pre-Fetching API的時(shí)候,我們一定要保證整個(gè)預(yù)加載的過程都放在后臺(tái)線程中進(jìn)行璧亮。合理使用GCD 和 NSOperationQueue處理好多線程萧诫。

  2. 請(qǐng)切記,Pre-Fetching API是一種自適應(yīng)的技術(shù)枝嘶。何為自適應(yīng)技術(shù)呢帘饶?當(dāng)我們滑動(dòng)速度很慢的時(shí)候,在這種“安靜”的時(shí)期群扶,Pre-Fetching API會(huì)默默的在后臺(tái)幫我們預(yù)加載數(shù)據(jù)及刻,但是一旦當(dāng)我們快速滑動(dòng),我們需要頻繁的刷新竞阐,我們不會(huì)去執(zhí)行Pre-Fetching API缴饭。

  3. 最后,用cancelPrefetchingAPI去迎合用戶的滑動(dòng)動(dòng)作的變換骆莹,比如說用戶在快速滑動(dòng)突然發(fā)現(xiàn)了有趣的感興趣的事情颗搂,這個(gè)時(shí)候停下來滑動(dòng)了,甚至快速反向滑動(dòng)了幕垦,或者點(diǎn)擊了事件丢氢,進(jìn)去看詳情了,這些時(shí)刻我們都應(yīng)該開啟cancelPrefetchingAPI先改。

綜上所述卖丸,Pre-Fetching API對(duì)于提高UICollectionView的性能提升是很有幫助的,而且并不需要加入太多的代碼盏道。加入少量的代碼就可以獲得巨大的性能提升!

三. UITableViewCell的Pre-Fetching預(yù)加載

在iOS 10中载碌,UITableViewCell也跟著UICollectionView一起得到了性能的提升猜嘱,一樣擁有了Pre-Fetching API衅枫。

protocol UITableViewDataSourcePrefetching {
    func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [NSIndexPath])
    optional func tableView(_ tableView: UITableView, cancelPrefetchingForRowsAt indexPaths:
                            [NSIndexPath])
}
class UITableView : UIScrollView {
    weak var prefetchDataSource: UITableViewDataSourcePrefetching?
}

這里和上面 UICollectionView一樣,會(huì)調(diào)用TableView prefetchRowsAt indexPaths方法朗伶。indexPaths還是一個(gè)有序數(shù)字弦撩,順序就是列表上可見的順序。第二個(gè)可選的API還是TableView cancelPrefetchingForRowsAt indexPaths论皆,和之前提到的一樣益楼,也是用來取消預(yù)加載的。性能的提升和UICollectionView一樣的点晴,對(duì)UITableView的性能提升很大感凤!

四. 針對(duì)self-sizing的改進(jìn)

self-sizing API 第一次被引入是在iOS 8,然而現(xiàn)在在iOS 10中得到了一些改進(jìn)粒督。

在UICollectionView 中有一個(gè)固定的類陪竿,叫UICollectionViewFlowLayout,iOS已經(jīng)在這個(gè)類中完全支持了self-sizing屠橄。為了能開啟這一特性族跛,需要我們開發(fā)者為一些不能為0的CGSize的cell設(shè)置一下estimated item size。


layout.estimatedItemSize = CGSize(width:50,height:50)

這會(huì)告訴UICollectionView我們想要開啟動(dòng)態(tài)計(jì)算內(nèi)容的布局锐墙。

至今礁哄,我們能有3種方法來動(dòng)態(tài)的布局。

  1. 第一種方法是使用autolayout
    當(dāng)我們合理的加上了constrain溪北,當(dāng)cell加載的時(shí)候桐绒,就會(huì)根據(jù)內(nèi)容動(dòng)態(tài)的加載布局。

  2. 第二種方法刻盐,如果你不想使用autolayout的方法掏膏,想更加手動(dòng)的控制它,那么我們就需要重寫sizeThatFits()方法敦锌。

  3. 第三種方法馒疹,終極的方法是重寫preferredLayoutAttributesFittingAttributes()方法。在這個(gè)方法里面不僅僅可以提供size的信息乙墙,更可以得到alpha和transform的信息颖变。

所以想指定cell的大小,就可以用上面3個(gè)方法之一听想。

但是實(shí)際操作中腥刹,我們可以發(fā)現(xiàn),有時(shí)候設(shè)置一個(gè)合適的estimated item size汉买,對(duì)于我們來說是很困難的事情衔峰。如果flow layout可以用數(shù)學(xué)的方法動(dòng)態(tài)的計(jì)算布局,而不是根據(jù)我們給的size去布局,那會(huì)是件很酷的事情垫卤。

iOS 10中就引入了新的API來解決上述的問題威彰。

layout.estimatedItemSize = UICollectionViewFlowLayoutAutomaticSize

對(duì)于開發(fā)者,我們需要做的事情穴肘,僅僅就是設(shè)置好flow layout 歇盼,然后給estimatedItemSize設(shè)定一個(gè)新的常數(shù), 最后UICollectionViewFlowLayout 就會(huì)自動(dòng)計(jì)算高度了。

系統(tǒng)會(huì)自動(dòng)計(jì)算好所有的布局评抚,包括已經(jīng)定下來的size的cell豹缀,并且還會(huì)動(dòng)態(tài)的給出接下來cell的大小的預(yù)測(cè)。

接下來看2個(gè)例子就可以很明顯看出iOS 10針對(duì)self-sizing的改進(jìn)了慨代。

上圖可以看到邢笙,iOS 9 的布局是針對(duì)單個(gè)cell計(jì)算的,當(dāng)改變了單個(gè)的cell鱼响,其他的cell依舊沒有變化鸣剪,還是需要重新計(jì)算。

這里例子就可以很明顯的看出差別了丈积。當(dāng)我們改變了第一個(gè)cell的size以后筐骇,系統(tǒng)會(huì)自動(dòng)計(jì)算出所有的cell的size,并且每一行江滨,每一個(gè)section的size都會(huì)被動(dòng)態(tài)的計(jì)算出來铛纬,并且刷新界面!

以上就是iOS 10針對(duì)self-sizing的改進(jìn)唬滑。

五. Interactive Reordering

談到重新排列告唆,這是我們就需要類比一下UITableView了,UICollectionView的重新排列就如同UITableView 把cell上下移動(dòng)晶密,只不過UITableView的重排是針對(duì)垂直方向的擒悬。

在iOS 9中,引入了UICollectionView的Interactive Reordering稻艰,在今年的iOS 10中懂牧,又加入了一些新的API。

在上圖中尊勿,我們可以看到僧凤,我們即使任意拖動(dòng)cell,整個(gè)界面也會(huì)重新排列元扔,并且我們改變了cell的大小躯保,整個(gè) UICollectionView 也會(huì)重新動(dòng)態(tài)的布局。

我們先來看看iOS 9里面的API


class UICollectionView : UIScrollView {
    func beginInteractiveMovementForItem(at indexPath: NSIndexPath) -> Bool
    func updateInteractiveMovementTargetPosition(_ targetPosition: CGPoint)
    func endInteractiveMovement()
    func cancelInteractiveMovement()
}

要想開啟interactive movement澎语,我們就需要調(diào)用beginInteractiveMovementForItem()方法途事,其中indexPath代表了我們將要移動(dòng)走的cell验懊。接著每次手勢(shì)的刷新,我們都需要刷新cell的位置盯孙,去響應(yīng)我們手指的移動(dòng)操作鲁森。這時(shí)我們就需要調(diào)用updateInteractiveMovementTargetPosition()方法。我們通過手勢(shì)來傳遞坐標(biāo)的變化振惰。當(dāng)我們移動(dòng)結(jié)束之后,就會(huì)調(diào)用endInteractiveMovement()方法垄懂。 UICollectionView 就會(huì)放下cell骑晶,處理完整個(gè)layout,此時(shí)你也可以重新刷新model或者處理數(shù)據(jù)model草慧。如果中間突然手勢(shì)取消了桶蛔,那么這個(gè)時(shí)候就應(yīng)該調(diào)用cancelInteractiveMovement()方法。如果我們重新把cell移動(dòng)一圈之后又放回原位漫谷,其實(shí)就是取消了移動(dòng)仔雷,那這個(gè)時(shí)候就應(yīng)該在cancelInteractiveMovement()方法里面不用去刷新data source。

在iOS 10中舔示,如果你使用UICollectionViewController碟婆,那么這個(gè)重排對(duì)于你來說會(huì)更加的簡(jiǎn)單。


class UICollectionViewController : UIViewController {
    var installsStandardGestureForInteractiveMovement: Bool
}

你只需要把installsStandardGestureForInteractiveMovement這個(gè)屬性設(shè)置為True即可惕稻。CollectionViewController會(huì)自動(dòng)為你加入手勢(shì)竖共,并且自動(dòng)為你調(diào)用上面的方法。

以上就是去年iOS 9為我們?cè)黾拥腁PI俺祠。

今年的iOS 10新加入的API是在iOS 9的基礎(chǔ)上增加了翻頁的功能公给。
UICollectionView繼承自UIScrollView,所以只需要你做的是把isPagingEnabled屬性設(shè)置為True蜘渣,即可開啟分頁的功能淌铐。


collectionView.isPagingEnabled = true

開啟分頁之前:

開啟分頁之后就長(zhǎng)這樣子:

每次移動(dòng)一次就會(huì)以頁為單位的翻頁。

六.UIRefreshControl

UIRefreshControl現(xiàn)在可以直接在CollectionView里面使用蔫缸,同樣的腿准,也可以直接在UITableView里面使用,并且可以脫離UITableViewController捂龄。因?yàn)楝F(xiàn)在RefreshControl成為了ScrollView的一個(gè)屬性了释涛。

UIRefreshControl的使用方法很簡(jiǎn)單,就三步:


let refreshControl = UIRefreshControl()
refreshControl.addTarget(self, action: #selector(refreshControlDidFire(_:)),
                         for: .valueChanged)
collectionView.refreshControl = refreshControl

先創(chuàng)建一個(gè)refreshControl倦沧,再關(guān)聯(lián)一個(gè)action事件唇撬,最后把這個(gè)新的refreshControl賦給想要的控件的對(duì)應(yīng)的屬性即可。

總結(jié)

通過以上展融,我們談到了以下的知識(shí):

  1. UICollectionView cell pre-fetching預(yù)加載機(jī)制
  2. UICollectionView and UITableView prefetchDataSource 新增的API
  3. 針對(duì)self-sizing cells 的改進(jìn)
  4. Interactive reordering

最后窖认,談?wù)勎铱戳薸OS 10 UICollectionView的優(yōu)化的看法吧,原來有些地方用到AsyncDisplayKit優(yōu)化UICollectionView速度的,現(xiàn)在可以考慮不用第三方庫優(yōu)化了扑浸,系統(tǒng)自帶的方法可以解決一般性的卡頓的問題了烧给。我感覺iOS 10的UICollectionView才像是一個(gè)完整版的,之前的系統(tǒng)優(yōu)化的都不夠喝噪。我還是很看好iOS 10的UICollectionView础嫡。

請(qǐng)大家多多指教。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末酝惧,一起剝皮案震驚了整個(gè)濱河市榴鼎,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌晚唇,老刑警劉巖巫财,帶你破解...
    沈念sama閱讀 219,427評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異哩陕,居然都是意外死亡平项,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門悍及,熙熙樓的掌柜王于貴愁眉苦臉地迎上來闽瓢,“玉大人,你說我怎么就攤上這事并鸵≡Х郏” “怎么了?”我有些...
    開封第一講書人閱讀 165,747評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵园担,是天一觀的道長(zhǎng)届谈。 經(jīng)常有香客問我,道長(zhǎng)弯汰,這世上最難降的妖魔是什么艰山? 我笑而不...
    開封第一講書人閱讀 58,939評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮咏闪,結(jié)果婚禮上曙搬,老公的妹妹穿的比我還像新娘。我一直安慰自己鸽嫂,他們只是感情好纵装,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著据某,像睡著了一般橡娄。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上癣籽,一...
    開封第一講書人閱讀 51,737評(píng)論 1 305
  • 那天挽唉,我揣著相機(jī)與錄音滤祖,去河邊找鬼。 笑死瓶籽,一個(gè)胖子當(dāng)著我的面吹牛匠童,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播塑顺,決...
    沈念sama閱讀 40,448評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼汤求,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了严拒?” 一聲冷哼從身側(cè)響起首昔,我...
    開封第一講書人閱讀 39,352評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎糙俗,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體预鬓,經(jīng)...
    沈念sama閱讀 45,834評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡巧骚,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評(píng)論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了格二。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片劈彪。...
    茶點(diǎn)故事閱讀 40,133評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖顶猜,靈堂內(nèi)的尸體忽然破棺而出沧奴,到底是詐尸還是另有隱情,我是刑警寧澤长窄,帶...
    沈念sama閱讀 35,815評(píng)論 5 346
  • 正文 年R本政府宣布滔吠,位于F島的核電站,受9級(jí)特大地震影響挠日,放射性物質(zhì)發(fā)生泄漏疮绷。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評(píng)論 3 331
  • 文/蒙蒙 一嚣潜、第九天 我趴在偏房一處隱蔽的房頂上張望冬骚。 院中可真熱鬧,春花似錦懂算、人聲如沸只冻。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽喜德。三九已至,卻和暖如春酸役,著一層夾襖步出監(jiān)牢的瞬間住诸,已是汗流浹背驾胆。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留贱呐,地道東北人丧诺。 一個(gè)月前我還...
    沈念sama閱讀 48,398評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像奄薇,于是被迫代替她去往敵國(guó)和親驳阎。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評(píng)論 2 355

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