iOS 高性能異構(gòu)滾動視圖構(gòu)建方案 — LazyScrollView

LazyScrollView :

  • 已開源空厌,可以直接使用cocoapods添加钝诚,Podfile 里面加一條 pod 'LazyScroll' 即可颖御。

  • Demo也在Github倉庫中,LazyScrollView Demo的詳細說明凝颇。


1潘拱、LazyScroll是什么

LazyScrollView 繼承自ScrollView,目標是解決異構(gòu)(與TableView的同構(gòu)對比)滾動視圖的復(fù)用回收問題拧略。它可以支持跨View層的復(fù)用芦岂,用易用方式來生成一個高性能的滾動視圖。此方案最先在天貓iOS客戶端的首頁落地垫蛆。

2禽最、為什么要用LazyScrollView

貓客首頁之前首頁的View比較少腺怯,不需要復(fù)用和回收也有很優(yōu)秀的性能,但是之后首頁的View數(shù)量逐漸膨脹川无,沒有一套復(fù)用回收機制的ScrollView已經(jīng)影響到性能了呛占,迫切需要處理對ScrollView中View的復(fù)用和回收。

使用TableView只能用來解決同類Cell的展示懦趋,而在貓客首頁這個ScrollView里面晾虑,View的種類太多了。不適合我們的場景愕够。

而UICollectionView本身的布局和復(fù)用回收機制不夠靈活走贪,用起來也較為繁瑣佛猛。并且本來貓客的首頁就有一套相對成熟的卡片布局方案惑芭。所以誕生了LazyScrollView去解決這個問題。

3继找、LazyScroll如何用

LazyScrollView的使用和TableView很像遂跟,不過多了一個需要實現(xiàn)的方法:返回對應(yīng)index的View 相對LazyScrollView的絕對坐標。

  • 實現(xiàn)LazyScrollViewDatasource

類似TableView的用法婴渡,我們需要使用方實現(xiàn)LazyScrollViewDatasource這個Delegate

@protocol TMMuiLazyScrollViewDataSource <NSObject>
@required
//ScrollView一共展示多少個item
- (NSUInteger)numberOfItemInScrollView:(TMMuiLazyScrollView *)scrollView;
//要求根據(jù)index直接返回RectModel
- (TMMuiRectModel *)scrollView:(TMMuiLazyScrollView *)scrollView rectModelAtIndex:(NSUInteger)index;
//返回下標所對應(yīng)的view
- (UIView *)scrollView:(TMMuiLazyScrollView *)scrollView itemByMuiID:(NSString *)muiID;
@end

LazyScrollView的核心是在初始狀態(tài)就得知所有View應(yīng)該顯示的位置幻锁。這個Protocol可以讓LazyScrollView獲取到這些信息。

第一個方法很簡單边臼,獲取LazyScrollView中item的個數(shù)哄尔。

第二個方法需要按照Index返回 TMMuiRectModel ,它會攜帶對應(yīng)index的View 相對LazyScrollView的絕對坐標柠并。TMMuiRectModel是這么個東西:

@interface TMMuiRectModel:NSObject
//轉(zhuǎn)換后的絕對值rect
@property (nonatomic,assign) CGRect absRect;
//業(yè)務(wù)下標
@property (nonatomic,copy) NSString *muiID;

@end

absRect 是LazyScroll中的View相對LazyScrollView的絕對坐標岭接,muiID 是這個View在LazyScrollView中唯一的標識符,可賦值也可不賦值臼予,不賦值的話LazyScroll會處理成轉(zhuǎn)換為字符串的下標鸣戴。如果這個標識符在Protocol的第三個方法中會用到。

第三個方法粘拾,返回View窄锅。首先,我們在UIView之外加了一個Category:

@interface UIView(TMMui)

//索引過的標識缰雇,在LazyScrollView范圍內(nèi)唯一
@property (nonatomic, copy) NSString  *muiID;
//重用的ID
@property (nonatomic, copy) NSString *reuseIdentifier;

這個category可以讓View攜帶muiID和reuseIdentifier,對于返回的View來說入偷,只需要在乎對View的reuseIdentifier賦值,muiID的賦值會在lazyScrollView中處理掉械哟。reuseIdentifier相同的View會被復(fù)用疏之,如果這個View的reuseIdentifier是nil或者空字符串,則不會被復(fù)用戒良。

  • 調(diào)用核心API
- (void)reloadData;

重新走一遍DataSource的這些方法体捏,等同于TableView中的reloadData

- (UIView *)dequeueReusableItemWithIdentifier:(NSString *)identifier

根據(jù)identifier獲取可以復(fù)用的View。和TableView的
dequeueReusableCellWithIdentifier:(NSString *)identifier 方法意義相同。通常是在 LazyScrollViewDatasource 第三個方法几缭,返回View的時候使用河泳。先嘗試獲取復(fù)用池中的View,如果沒有再去新建年栓。

4拆挥、LazyScrollView的內(nèi)部實現(xiàn)

這是一個Demo, 被復(fù)用的View,標記的backgroundColor會和之前生成的時候有所不同某抓。


STEP 1 根據(jù)DataSource獲取所有的TMMuiRectModel

根據(jù)DataSource的Delegate纸兔,拿到所有的View應(yīng)該被顯示的位置。這一步否副,核心是拿到的位置是確定的汉矿。

根據(jù)Demo,我們觀察從 0/1 - 2/3 之間這些View

這個時候LazyScrollView拿到的Rect如下:


STEP 2 排序

拿到了這些位置之后备禀,接下來做的事情就是排序洲拇。排序生成的索引會有兩個:根據(jù)頂邊(y)升序排序的索引和根據(jù)底邊(y+height)降序排序的索引。

根據(jù)頂邊(y)升序排序的索引:

根據(jù)底邊(y+height)降序排序的索引:

STEP 3 查找

前兩步是在執(zhí)行完reload曲尸,在視圖還沒有生成的時候就開始做了赋续,而接下來的步驟在要生成視圖(初始化或滾動的時候)才會去做。

我們設(shè)定了Buffer為上下各20另患,滾動超過20個像素后才會指定查找視圖并顯示的動作纽乱。

接下來就是找哪些View應(yīng)該被顯示了。舉個例子昆箕,如下圖鸦列,紅圈是應(yīng)該顯示的區(qū)域。


現(xiàn)在已知的是紅圈頂邊y是242为严,底邊y是949敛熬,加上緩沖區(qū)Buffer,應(yīng)該是找222 - 969 之間的View第股。我們要做的是应民,找到頂邊y小于969的Model底邊y+height大于222的Model,取交集夕吻,就是我們要顯示的View

采用的方法為二分查找诲锹,在根據(jù)頂邊升序排序的索引中找969,找到的index為0(MUIID為2/2)涉馅,我們使用一個Set归园,把根據(jù)頂邊排序中index >= 0 的元素先放在這里。獲取的Set中包含的muiID為 0/0,0/1,0/2,0/3,1/0,1/1,1/2,1/3,2/0,2/1,2/2稚矿。

根據(jù)底邊排序的索引中找222庸诱,找到的index為2捻浦,我們把index >= 2的元素放在另一個Set,獲取的Set中包含的muiID為0/2,0/3,1/0,1/1,1/2,1/3,2/0,2/1,2/2
兩個Set取交集桥爽,得到的就是我們的ResultSet朱灿,這里面都是我們要顯示View的Model,它們的muiID是0/2,0/3,1/0,1/1,1/2,1/3,2/0,2/1,2/2钠四。

STEP 4 回收盗扒、復(fù)用、生成

我們知道了應(yīng)該顯示哪些View缀去,但是我們之后做的第一步是把不需要顯示的View加入到復(fù)用池中侣灶。

LazyScroll可以取到當前顯示了的View,拿當前顯示的View的muiID和將要顯示view的Model的muiID做對比缕碎,可以知道當前顯示的View哪些應(yīng)該被回收褥影。

LazyScrollView中有一個Dictionary,key是reuseIdentifier,Value是對應(yīng)reuseIdentifier被回收的View阎曹,當LazyScrollView得知這個View不該再出現(xiàn)了伪阶,會把View放在這里,并且把這個View hidden掉处嫌。

接下來,LazyScrollView會去調(diào)用datasource的 - (UIView *)scrollView:(TMMuiLazyScrollView *)scrollView itemByMuiID:(NSString *)muiID; 復(fù)用還是不復(fù)用斟湃,是由datasource決定的熏迹。如果要復(fù)用,需要datasource方法內(nèi)調(diào)用 - (UIView *)dequeueReusableItemWithIdentifier:(NSString *)identifier 獲取復(fù)用的View凝赛,這個方法取出來的View就是在上一段所說的Dictionary中拿的注暗。

這樣,我們就完成了一次完整的循環(huán) : 找到所有View將要顯示的位置 – 排序 – 查找應(yīng)該顯示的View – 回收 – 創(chuàng)建/復(fù)用墓猎。

5捆昏、最后

LazyScroll的復(fù)用和回收能力是比較強大的,在貓客首頁使用之后毙沾,因為View數(shù)量而導(dǎo)致內(nèi)存過多的問題得到了解決骗卜。

在這套復(fù)用和回收機制的加持之下,我們將LazyScrollView繼續(xù)延伸左胞,構(gòu)造出一套完整的布局解決方案 Tangram寇仓,它將Native中View的布局方式變得更動態(tài)化,敬請期待烤宙。

轉(zhuǎn)載出處:蘋果核 - iOS 高性能異構(gòu)滾動視圖構(gòu)建方案 —— LazyScrollView

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末遍烦,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子躺枕,更是在濱河造成了極大的恐慌服猪,老刑警劉巖供填,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異罢猪,居然都是意外死亡捕虽,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進店門坡脐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來泄私,“玉大人,你說我怎么就攤上這事备闲∩味耍” “怎么了?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵恬砂,是天一觀的道長咧纠。 經(jīng)常有香客問我,道長泻骤,這世上最難降的妖魔是什么漆羔? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮狱掂,結(jié)果婚禮上演痒,老公的妹妹穿的比我還像新娘。我一直安慰自己趋惨,他們只是感情好鸟顺,可當我...
    茶點故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著器虾,像睡著了一般讯嫂。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上兆沙,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天欧芽,我揣著相機與錄音,去河邊找鬼葛圃。 笑死千扔,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的装悲。 我是一名探鬼主播昏鹃,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼诀诊!你這毒婦竟也來了洞渤?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤属瓣,失蹤者是張志新(化名)和其女友劉穎载迄,沒想到半個月后讯柔,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡护昧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年魂迄,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片惋耙。...
    茶點故事閱讀 40,115評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡捣炬,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出绽榛,到底是詐尸還是另有隱情湿酸,我是刑警寧澤,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布灭美,位于F島的核電站推溃,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏届腐。R本人自食惡果不足惜铁坎,卻給世界環(huán)境...
    茶點故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望犁苏。 院中可真熱鬧硬萍,春花似錦、人聲如沸傀顾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽短曾。三九已至,卻和暖如春赐劣,著一層夾襖步出監(jiān)牢的瞬間嫉拐,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工魁兼, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留婉徘,地道東北人。 一個月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓咐汞,卻偏偏與公主長得像盖呼,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子化撕,可洞房花燭夜當晚...
    茶點故事閱讀 45,055評論 2 355

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