(轉(zhuǎn))【W(wǎng)WDC2016 Session筆記】 iOS 10 UICollectionView新特性

1467784294969170.png

原文地址:http://www.cocoachina.com/ios/20160706/16952.html

前言

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

  • 順滑的滑動(dòng)體驗(yàn)

現(xiàn)在基本上人人都離不開手機(jī),手機(jī)的app也每天都有人在用。一個(gè)app的好壞由它的用戶體驗(yàn)決定。在可以滑動(dòng)的視圖里面瘾敢,必須要更加絲滑柔順才能獲得用戶的青睞。這些UICollectionView的新特性可以讓你們的app比原來(lái)更加順滑尿这,而且這些特性只需要你加入少量的代碼即可達(dá)到目的簇抵。

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

self-sizing的API在iOS8的時(shí)候被引進(jìn),iOS10中加入更多特性使cell更加容易去適配射众。

  • Interactive reordering重排

這個(gè)功能在iOS9的時(shí)候介紹過(guò)了碟摆,蘋果在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)。而且很大一部分的操作是來(lái)自于用戶的滑動(dòng)操作罗洗。所以滑動(dòng)的順滑是使用戶沉浸在app中享受的必要條件愉舔。接下來(lái)我們就談?wù)刬OS 10 中增加了那些新特性。
我們先來(lái)看一下之前 UICollectionView 的體驗(yàn)伙菜,假設(shè)我們每個(gè)cell都是簡(jiǎn)單的藍(lán)色轩缤,實(shí)際開發(fā)app中,cell會(huì)比這復(fù)雜很多仇让。 我們先生成100個(gè)cell。當(dāng)用戶滑動(dòng)不是很快的時(shí)候躺翻,還感覺不出來(lái)卡頓丧叽,當(dāng)用戶大幅度滑動(dòng),整個(gè)UICollectionView的卡頓就很明顯了公你。如果整個(gè)cell的DataSource又是從網(wǎng)絡(luò)加載的踊淳,那就更加卡頓了。效果如下圖。

1467784344928825.gif

如果這種app上架迂尝,用戶使用過(guò)后脱茉,很可能就直接給1星評(píng)價(jià)了。但是為什么會(huì)造成這種問(wèn)題呢垄开?我們來(lái)分析一下琴许,我們模擬一下系統(tǒng)如何處理重用機(jī)制的,效果如下圖溉躲。

1467784355209022.gif

在上圖中榜田,我們可以看出,當(dāng)cell準(zhǔn)備加載進(jìn)屏幕的時(shí)候锻梳,整個(gè)cell都已經(jīng)加載完成箭券,等待在屏幕外面了。而且更重要的是疑枯,在屏幕外面等待加載的cell是整整一行辩块!這一行的cell都已經(jīng)加載完數(shù)據(jù)。這是UICollectionView在用戶大幅度滑動(dòng)時(shí)卡頓的根本原因荆永。用專業(yè)的術(shù)語(yǔ)來(lái)說(shuō)废亭,掉幀

接下來(lái)我們就來(lái)詳細(xì)的說(shuō)說(shuō)掉幀的問(wèn)題屁魏。

當(dāng)今的用戶是很挑剔的滔以,用戶需要一個(gè)很順滑的體驗(yàn),只要有一點(diǎn)卡頓氓拼,很可能一言不合就卸載app了你画。要想用戶感覺不到卡頓,那么我們的app必須幀率達(dá)到60幀/秒桃漾。用數(shù)學(xué)換算一下就是每幀16毫秒就必須刷新一次坏匪。
我們用圖標(biāo)來(lái)分析一下掉幀的問(wèn)題。下面會(huì)出現(xiàn)2種不同的幀撬统。

  • 1.第一種情況适滓,下圖是當(dāng)用戶輕微的上下小幅度滑動(dòng)。這個(gè)時(shí)候每個(gè)cell的加載壓力都不大恋追,iOS針對(duì)這種情況凭迹,已經(jīng)做了很好的優(yōu)化了,所以用戶感覺不到任何卡頓苦囱。這種情況是不會(huì)掉幀嗅绸,用戶也希望能使用如此順滑的app。
1467784433822879.jpg
  • 2.第二種情況撕彤,當(dāng)用戶大幅度滑動(dòng)鱼鸠,每個(gè)cell加載的壓力很大,也許需要網(wǎng)絡(luò)請(qǐng)求,也許需要讀取數(shù)據(jù)庫(kù)蚀狰,而且每次都加載一行cell出來(lái)愉昆,這樣每個(gè)cell的加載時(shí)間都增加了,加載一行的總時(shí)間也就大大增加了麻蹋,如下圖所示跛溉。這樣,不僅僅當(dāng)前幀在加載cell哥蔚,總的時(shí)間還會(huì)擠壓到下一幀的時(shí)間里面去倒谷。這種情況下,用戶就感覺到了卡頓了糙箍。
1467784459878847.jpg

我們換種方式在說(shuō)明一下2種情況下掉幀的情況渤愁。我們用下圖的標(biāo)準(zhǔn)來(lái)衡量一下上面2種情況。下圖分為2部分深夯,上面紅色的區(qū)域抖格,就是表示掉幀的區(qū)域,因?yàn)楦哂?6ms咕晋。紅色和綠色區(qū)域的分界線就在16ms處雹拄。y軸我們表示的是CPU在主線程中花費(fèi)的時(shí)間。x軸表示的是在用戶滑動(dòng)中發(fā)生的刷新事件掌呜。

1467784491910972.jpg

針對(duì)上述掉幀的情況滓玖,繪制出實(shí)驗(yàn)數(shù)據(jù),如下圖质蕉。值得我們關(guān)注的是势篡,曲線是很曲折的,非常的不平滑模暗。當(dāng)用戶大幅度滑動(dòng)的時(shí)候禁悠,峰值超過(guò)了16ms,當(dāng)用戶慢速滑動(dòng)的時(shí)候兑宇,幀率又能保持在比較順滑的區(qū)域碍侦。處于綠色區(qū)域內(nèi)的cell加載壓力都是很小的。這就是時(shí)而掉幀時(shí)而順滑的場(chǎng)景隶糕。這種場(chǎng)景下瓷产,用戶體驗(yàn)是很糟糕的。

1467784519648239.jpg
那怎么解決這么問(wèn)題的呢枚驻?我們來(lái)看下圖:
1467784547235875.jpg

上圖中的曲線我們看著就很平緩了濒旦,而且這種情況也不會(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的生命周期了慷荔。

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

1467784605179969.jpg

這個(gè)時(shí)候我們把這個(gè)cell從reuse隊(duì)列里面拿出來(lái),然后調(diào)用prepareForReuse方法壹士。這個(gè)方法就給了cell時(shí)間磷雇,用來(lái)重置cell,重置狀態(tài)躏救,刷新cell唯笙,加載新的數(shù)據(jù)。

1467784613342397.jpg

再滑動(dòng)盒使,我們就會(huì)調(diào)用cellForItemAtIndexPath方法了崩掘。這個(gè)方法里面就是我們開發(fā)者自定義的填充cell的方式了。這里會(huì)填充data model少办,然后賦值給cell苞慢,再把cell返回給iOS系統(tǒng)。

1467784643684182.jpg

當(dāng)cell馬上要進(jìn)入屏幕的時(shí)候英妓,就會(huì)調(diào)用willDisplayCell的方法挽放。這個(gè)方法給了我們app最后一次機(jī)會(huì),為cell進(jìn)入屏幕做最后的準(zhǔn)備工作鞋拟。執(zhí)行完willDisplayCell之后骂维,cell就進(jìn)入屏幕了。

1467784674667370.jpg

當(dāng)cell完全離開屏幕之后贺纲,就會(huì)調(diào)用didEndDisplayingCell方法航闺。以上就是在iOS10之前的整個(gè)UICollectionViewCell的生命周期。
接下來(lái)我們就來(lái)看看iOS 10的UICollectionViewCell生命周期是怎么樣的猴誊。

1467784919171617.jpg

這里還是和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í)候列赎。

1467784950618167.jpg

這里還是和之前一樣宏悦,在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感耙。

1467785001420508.jpg

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

1467785009176155.jpg

當(dāng)整個(gè)cell要從UICollectionView的可見區(qū)域消失的時(shí)候即硼,這個(gè)時(shí)候會(huì)調(diào)用didEndDisplayingCell方法逃片。接下來(lái)發(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滑出屏幕后十饥,如果突然又想回來(lái)窟勃,這個(gè)時(shí)候cell并不需要再走一段的生命周期了。只需要直接調(diào)用willDisplayCell就可以了逗堵。cell就又會(huì)重新出現(xiàn)在屏幕中秉氧。這就是iOS 10 的整個(gè)UICollectionView的生命周期。

1467785140434098.jpg
1467785147242971.jpg
1467785156440182.jpg
1467785162269537.jpg
1467785168247905.jpg

上面說(shuō)的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)在屏幕上了轰驳。

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

讓我們來(lái)看看上述的改動(dòng)對(duì)滑動(dòng)的影響
1467785199429168.gif

滑動(dòng)比iOS 9流程很多级解,這里可以看到整個(gè)過(guò)程都很平緩,不卡頓田绑。
還是和iOS 9一樣勤哗,我們來(lái)模擬一下系統(tǒng)是如何加載cell的情況。

1467785382812684.gif

我們可以很明顯的看到掩驱,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í)在是太棒了F床浴!

二. 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即可伤哺。

collectionView.isPrefetchingEnabled = false

為了最佳實(shí)踐一下這個(gè)新特性燕侠。我們先改變一下我們加載cell的方式。我們把很重的讀取數(shù)據(jù)的操作立莉,所有內(nèi)容的創(chuàng)建都放到cellForItemAtIndexPath方法里面去完成贬循。保證我們?cè)趙illDisplayCell 和 didEndDisplayCell這兩個(gè)方法里面基本不做其他事情。最后桃序,保證cellForItemAtIndexPath加載的cell都不是從重用隊(duì)列里面拿出來(lái)的杖虾。
如果這個(gè)時(shí)候當(dāng)你用iOS 10編譯出你的app,那么非常順滑的用戶體驗(yàn)就會(huì)自動(dòng)的優(yōu)化出來(lái)媒熊。

UICollectionView的流暢的滑動(dòng)解決了奇适,那么在UICollectionViewCell在加載的時(shí)候所花費(fèi)的時(shí)間坟比,怎么解決呢?嚷往?

UICollectionViewCell加載的時(shí)間取決于DataModel葛账。DataModel很可能回去加載圖片,來(lái)自于網(wǎng)絡(luò)或者來(lái)自于本地的數(shù)據(jù)庫(kù)皮仁。這些操作大多數(shù)都是異步的操作籍琳。為了使data加載更快,iOS 10引入了新的API來(lái)解決這個(gè)問(wèn)題贷祈。
UICollectionView有2個(gè)“小伙伴”趋急,那就是data source和delegate。在iOS 10中势誊,將會(huì)迎來(lái)第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)用查近,用來(lái)給你異步的預(yù)加載數(shù)據(jù)的。indexPaths數(shù)組是有序的挤忙,就是接下來(lái)item接收數(shù)據(jù)的順序霜威,讓我們model異步處理數(shù)據(jù)更加方便。

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

值得說(shuō)明的是茄厘,新增加的這個(gè)“小伙伴”prefetchDataSource并不能代替原來(lái)的讀取數(shù)據(jù)的方法矮冬,這個(gè)預(yù)加載僅僅只是輔助加載數(shù)據(jù),并不能
刪除原來(lái)我們讀取數(shù)據(jù)的方法次哈。

至此胎署,我們來(lái)看看從文章開始到現(xiàn)在,UICollectionView的性能提升了多少窑滞。我們還是用掉幀的方法來(lái)看看UICollectionView的性能琼牧。

1467785413182613.jpg

上圖是iOS 9 UICollectionView的性能,很明顯的看見哀卫,波峰波谷很明顯巨坊,并且還掉了8幀,有明顯的卡頓現(xiàn)象此改。

1467785449871270.jpg

上圖是iOS 10 UICollectionView的性能趾撵,我們可以很明顯的看到,經(jīng)過(guò)iOS 10的優(yōu)化共啃,整個(gè)曲線很明顯平緩了一些占调,沒有極端的波峰掉幀現(xiàn)象暂题。但是依舊存在少量的波峰快到16ms分界線了。

1467785482131029.jpg

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

先來(lái)總結(jié)一下使用Pre-Fetching API需要注意的地方。
  • 在我們使用Pre-Fetching API的時(shí)候想括,我們一定要保證整個(gè)預(yù)加載的過(guò)程都放在后臺(tái)線程中進(jìn)行。合理使用GCD 和 NSOperationQueue處理好多線程烙博。
  • 請(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详瑞。
  • 最后掂林,用cancelPrefetchingAPI去迎合用戶的滑動(dòng)動(dòng)作的變換,比如說(shuō)用戶在快速滑動(dòng)突然發(fā)現(xiàn)了有趣的感興趣的事情坝橡,這個(gè)時(shí)候停下來(lái)滑動(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衅檀,和之前提到的一樣,也是用來(lái)取消預(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種方法來(lái)動(dòng)態(tài)的布局:

  • 第一種方法是使用autolayout
  • 當(dāng)我們合理的加上了constrain状知,當(dāng)cell加載的時(shí)候秽五,就會(huì)根據(jù)內(nèi)容動(dòng)態(tài)的加載布局。
  • 第二種方法饥悴,如果你不想使用autolayout的方法坦喘,想更加手動(dòng)的控制它,那么我們就需要重寫sizeThatFits()方法西设。
  • 第三種方法瓣铣,終極的方法是重寫preferredLayoutAttributesFittingAttributes()方法。在這個(gè)方法里面不僅僅可以提供size的信息贷揽,更可以得到alpha和transform的信息坯沪。

所以想指定cell的大小,就可以用上面3個(gè)方法之一擒滑。
但是實(shí)際操作中腐晾,我們可以發(fā)現(xiàn),有時(shí)候設(shè)置一個(gè)合適的estimated item size丐一,對(duì)于我們來(lái)說(shuō)是很困難的事情藻糖。如果flow layout可以用數(shù)學(xué)的方法動(dòng)態(tài)的計(jì)算布局,而不是根據(jù)我們給的size去布局库车,那會(huì)是件很酷的事情巨柒。
iOS 10中就引入了新的API來(lái)解決上述的問(wèn)題。

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)定下來(lái)的size的cell正罢,并且還會(huì)動(dòng)態(tài)的給出接下來(lái)cell的大小的預(yù)測(cè)。
接下來(lái)看2個(gè)例子就可以很明顯看出iOS 10針對(duì)self-sizing的改進(jìn)了驻民。

1467785547586106.gif

上圖可以看到翻具,iOS 9 的布局是針對(duì)單個(gè)cell計(jì)算的,當(dāng)改變了單個(gè)的cell回还,其他的cell依舊沒有變化裆泳,還是需要重新計(jì)算。

1467785653922069.gif

這里例子就可以很明顯的看出差別了柠硕。當(dāng)我們改變了第一個(gè)cell的size以后工禾,系統(tǒng)會(huì)自動(dòng)計(jì)算出所有的cell的size,并且每一行蝗柔,每一個(gè)section的size都會(huì)被動(dòng)態(tài)的計(jì)算出來(lái)闻葵,并且刷新界面!
以上就是iOS 10針對(duì)self-sizing的改進(jìn)诫咱。

五. Interactive Reordering

談到重新排列笙隙,這是我們就需要類比一下UITableView了洪灯,UICollectionView的重新排列就如同UITableView 把cell上下移動(dòng)坎缭,只不過(guò)UITableView的重排是針對(duì)垂直方向的。
在iOS 9中签钩,引入了UICollectionView的Interactive Reordering掏呼,在今年的iOS 10中,又加入了一些新的API铅檩。

1467785697559422.gif

在上圖中憎夷,我們可以看到,我們即使任意拖動(dòng)cell昧旨,整個(gè)界面也會(huì)重新排列拾给,并且我們改變了cell的大小,整個(gè) UICollectionView 也會(huì)重新動(dòng)態(tài)的布局兔沃。
我們先來(lá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()方法窍侧。我們通過(guò)手勢(shì)來(lái)傳遞坐標(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ì)于你來(lái)說(shuō)會(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ǔ)上增加了翻頁(yè)的功能篮幢。
UICollectionView繼承自UIScrollView,所以只需要你做的是把isPagingEnabled屬性設(shè)置為True为迈,即可開啟分頁(yè)的功能三椿。

collectionView.isPagingEnabled = **true**

開啟分頁(yè)之前:

1467785741500789.gif

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

1467785759631412.gif

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

六.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é)

通過(guò)以上鸭栖,我們談到了以下的知識(shí):

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

最后歌馍,談?wù)勎铱戳薸OS 10 UICollectionView的優(yōu)化的看法吧,原來(lái)有些地方用到AsyncDisplayKit優(yōu)化UICollectionView速度的纤泵,現(xiàn)在可以考慮不用第三方庫(kù)優(yōu)化了骆姐,系統(tǒng)自帶的方法可以解決一般性的卡頓的問(wèn)題了镜粤。我感覺iOS 10的UICollectionView才像是一個(gè)完整版的,之前的系統(tǒng)優(yōu)化的都不夠玻褪。我還是很看好iOS 10的UICollectionView肉渴。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市带射,隨后出現(xiàn)的幾起案子同规,更是在濱河造成了極大的恐慌,老刑警劉巖窟社,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件券勺,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡灿里,警方通過(guò)查閱死者的電腦和手機(jī)关炼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)匣吊,“玉大人儒拂,你說(shuō)我怎么就攤上這事∩В” “怎么了社痛?”我有些...
    開封第一講書人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)命雀。 經(jīng)常有香客問(wèn)我蒜哀,道長(zhǎng),這世上最難降的妖魔是什么吏砂? 我笑而不...
    開封第一講書人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任撵儿,我火速辦了婚禮,結(jié)果婚禮上赊抖,老公的妹妹穿的比我還像新娘统倒。我一直安慰自己寨典,他們只是感情好氛雪,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著耸成,像睡著了一般报亩。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上井氢,一...
    開封第一講書人閱讀 49,007評(píng)論 1 284
  • 那天弦追,我揣著相機(jī)與錄音,去河邊找鬼花竞。 笑死劲件,一個(gè)胖子當(dāng)著我的面吹牛掸哑,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播零远,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼苗分,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了牵辣?” 一聲冷哼從身側(cè)響起摔癣,我...
    開封第一講書人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎纬向,沒想到半個(gè)月后择浊,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡逾条,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年琢岩,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了庆尘。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片犹褒。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡垒酬,死狀恐怖浩嫌,靈堂內(nèi)的尸體忽然破棺而出砰粹,到底是詐尸還是另有隱情瞳脓,我是刑警寧澤锋玲,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布蜗字,位于F島的核電站汤徽,受9級(jí)特大地震影響娩缰,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜谒府,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一拼坎、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧完疫,春花似錦泰鸡、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至芳誓,卻和暖如春余舶,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背锹淌。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工匿值, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人赂摆。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓挟憔,卻偏偏與公主長(zhǎng)得像钟些,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子绊谭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

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