這是 Texture 文檔系列翻譯迷捧,其中結(jié)合了自己的理解和工作中的使用體會。如果哪里有誤,希望指出朴译。
Layer Backing
通過使用 layer 而非 view 可以顯著提高 app 性能蟆融,推薦在不需要觸摸事件的 node 中開啟 layer-backing草巡。
在UIKit
中,手動將基于視圖的代碼轉(zhuǎn)換為 layer 很費力型酥,并且在需要啟用觸摸處理或其他特定于視圖的功能時山憨,需要手動將所有內(nèi)容轉(zhuǎn)換回去查乒。
在 Texture 中,將 node 的視圖及所有 subtree 轉(zhuǎn)換為 layer 非常簡單:
rootNode.isLayerBacked = YES;
需要轉(zhuǎn)換回 view 時郁竟,只需刪除這一行玛迄。
子樹柵格化 Subtree Rasterization
將整個視圖層級合成為一個圖層可以提高性能,但在UIKit
中會影響可維護(hù)性和基于層級結(jié)構(gòu)的推理棚亩。
在 node 中蓖议,開啟合成非常簡單:
[rootNode enableSubtreeRasterization];
上述代碼使從 rootNode 開始整個 node 層次結(jié)構(gòu)合成為一層。
同步并發(fā) Synchronous Concurrency
ASViewController
和ASCellNode
都有一個布爾類型neverShowPlaceholders
屬性蔑舞。通過將此屬性設(shè)置為YES
拒担,cell 或視圖控制器的 view 繪制完成前主線程將被堵塞。
開啟該屬性后攻询,并不能充分利用 Texture 的性能从撼。通常 node 已被預(yù)加載,在進(jìn)入屏幕時即將完成钧栖,因此堵塞時間很短低零。即使rangeTuningParameters
設(shè)置為0,Texture 性能也優(yōu)于UIKit
拯杠。因為即使主線程堵塞掏婶,subnode 也在并發(fā)執(zhí)行。
查看NSSpain 2015 talk video了解其具體行為:
node.neverShowPlaceholders = YES;
通常潭陪,cell 繪制完成前進(jìn)入了屏幕會顯示占位符雄妥,直到繪制完成。將neverShowPlaceholders
設(shè)置為YES
使 Texture 更像UIKit
依溯,即滑動時會像UIKit
一樣掉幀老厌,盡管 Texture 速度會快些。
圓角 Corner Rounding
對于圓角處理黎炉,很多開發(fā)人員都會選擇CALayer
的cornerRadius
屬性枝秤。但cornerRadius
會嚴(yán)重影響性能,應(yīng)在沒有其他選擇時才使用慷嗜。這一部分將涵蓋:
- 為何不應(yīng)使用
CALayer
的cornerRadius
淀弹。 - 其他更為高效實現(xiàn)圓角方式,以及何時使用庆械。
- 選擇圓角處理的流程圖薇溃。
- Texture 實現(xiàn)圓角的方法。
CALayer 的 cornerRadius 耗費性能
使用CALayer
的cornerRadius
會觸發(fā)離屏渲染(offscreen rendering)缭乘,以在每幀上執(zhí)行裁剪操作痊焊。滾動時每秒需要在60幀上執(zhí)行裁剪操作,即使內(nèi)容沒有發(fā)生任何變化。這意味著 GPU 必須在每幀之間切換上下文薄啥,包括合成整個幀和裁剪辕羽。
這些對性能的消耗不會顯示在 Time Profiler 中,因為其影響的是 CoreAnimation Render Server垄惧,會造成掉幀刁愿。
圓角策略
當(dāng)選擇圓角策略時,只需考慮以下三點:
- 圓角下(movement underneath the corner)是否有滑動到逊。
- 是否有穿過圓角滑動(movement through the corner)铣口。
- 四個圓角是否處于同一個 node 上,有沒有與其他 node 相交觉壶。
圓角下滑動是指圓角后面的任何運動脑题。例如,當(dāng)一個圓角 cell 在背景上滾動時铜靶,背景就是在圓角下滑動叔遂。
為了描述穿過圓角滑動,可以想象一個小的圓角滾動視圖争剿,其中包含大很多的圖片已艰。當(dāng)在滾動視圖內(nèi)縮放、平移圖片時蚕苇,照片將在滾動視圖的各個角中穿過哩掺。
上圖中,藍(lán)色表示圓角下有滑動涩笤;橙色表示穿過圓角滑動嚼吞。
圓角對象內(nèi)部有移動,而無需移過角蹬碧。下圖顯示了以綠色標(biāo)志的內(nèi)容舱禽,該內(nèi)容從邊緣開始插入,其邊距等于圓半徑大小锰茉。當(dāng)內(nèi)容滾動時,它不會在角落滾動切心。
使用上述方法來調(diào)整設(shè)計以消除圓角移動的影響飒筑,以便不影響性能的情況下使用cornerRadius
。
最后需要注意是否四個角處于同一個 node 中绽昏,或 subnode 與圓角相交协屡。
預(yù)合成角 Precomposited Corners
預(yù)合成角指使用貝塞爾曲線繪制角的曲線,以在 CGContext / UIGraphicsContext 中剪切內(nèi)容全谤。在這種情況下肤晓,拐角將成為圖像本身的一部分,并被同步到CALayer
中,有兩種類型的預(yù)合成角:
最佳方案為使用預(yù)合成的不透明角(precomposited opaque corner)补憾,這是最高效的方法漫萄,可實現(xiàn)零 alpha 混合(盡管這比避免觸發(fā)屏外渲染的重要性小很多),但其不夠靈活盈匾。如果圓角的對象需要移動腾务,則后面的背景將需要為純色。使用 Texture 或圖片背景會很棘手削饵,推薦使用預(yù)合成的 alpha 角岩瘦。
第二種涉及貝塞爾曲線的角是預(yù)合成 alpha 角(precomposited alpha corner),此方法非常靈活窿撬,是最常用的方法之一启昧。其會增加在這個內(nèi)容上進(jìn)行 alpha 混合的成本,并且 alpha 通道不透明會增加25%內(nèi)存消耗劈伴,但這些消耗對于現(xiàn)代設(shè)備來說很小密末,與cornerRadius
觸發(fā)的離屏渲染不在同一數(shù)量級。
預(yù)合成角要求角必須在同一 node宰啦,且不與 subnode 相交苏遥。不滿足任一條件,則需使用裁剪圓角赡模。
當(dāng)使用了shouldRasterizeDescendants
后田炭,Texture 會自動對cornerRadius
進(jìn)行預(yù)合成。在開啟柵格化前漓柑,請務(wù)必仔細(xì)考慮教硫,具體可以查看子樹柵格化 Subtree Rasterization
Texture 的
UIImage+ASConveniences.h
提供了簡單、純色圓角實現(xiàn)方法辆布,支持 alpha 和不透明創(chuàng)建平面顏色瞬矩,圓角可以調(diào)整大小,非常適合于圖像 node 和ASButtonNode
的背景占位符锋玲。
剪裁圓角 Clip Corner
Clip corner 通過向四個角放置四個不透明內(nèi)容實現(xiàn)圓角景用。這種方法靈活、性能高惭蹂。四個單獨 layer 對于 CPU 來說性能消耗很少伞插。
Clip Corner 適用于以下兩種情況:
- 四個角在不同 node,或與 subnode 相交盾碗。
- 圓角只在 node 頂部媚污。
是否可以使用CALayer的cornerRadius
雖然很少、但也存在必須使用cornerRadius
的情況廷雅。例如耗美,在實現(xiàn)動畫時京髓,圓角下滑動、穿過圓角的內(nèi)容是動態(tài)的商架,但通逞咴梗可以通過改變設(shè)計利用前面的解決方案。
屏幕沒有任何滑動時甸私,使用cornerRadius
對性能的影響小很多诚些。只要屏幕有滑動,即使不涉及圓角部分皇型,也會因使用cornerRadius
對性能產(chǎn)生影響诬烹。例如,導(dǎo)航欄中有一個圓形元素弃鸦,其下方有滾動視圖绞吁,即使它們不重疊,也會產(chǎn)生影響唬格〖移疲滑動屏幕上任何內(nèi)容,均會對性能產(chǎn)生影響购岗,即使用戶沒有與其交互汰聋。此外,任何類型的屏幕刷新喊积,都將因cornerRadius
而產(chǎn)生額外開銷烹困。
Rasterization 和 Layerbacking
雖然使用CALayer
的shouldRasterize
可以提高cornerRadius
的性能,但這是一個未充分理解的選項乾吻,通常很危險髓梅。在無需重新柵格化時(即沒有滑動、點擊更改顏色绎签,也不在移動的表視圖上)枯饿,可以使用shouldRasterize
屬性。通常诡必,不建議使用shouldRasterize
奢方,其可能會導(dǎo)致更為嚴(yán)重的性能下降。對于本身性能不佳爸舒、堅持使用cornerRadius
屬性的app來說蟋字,其能夠帶來一定的性能提升。但如果正從零構(gòu)建一款 app碳抄,強烈建議選擇前面更好的圓角策略愉老。
CALayer
的shouldRasterize
與 Texture 的node.shouldRasterizeDescendents
無關(guān)场绿,當(dāng)開啟shouldRasterizeDescendents
后剖效,將阻止 subnode 創(chuàng)建 view 和 layer嫉入。
圓角策略選取
使用下面流程圖選取合適圓角策略:
Texture 實現(xiàn)圓角的方式
在 Texture 中,有以下幾種實現(xiàn)圓角的方式璧尸。
使用 cornerRadius
CGFloat cornerRadius = 20.0;
_photoImageNode.cornerRoundingType = ASCornerRoundingTypeDefaultSlowCALayer;
_photoImageNode.cornerRadius = cornerRadius;
使用 precomposition
CGFloat cornerRadius = 20.0;
_photoImageNode.cornerRoundingType = ASCornerRoundingTypePrecomposited;
_photoImageNode.cornerRadius = cornerRadius;
使用 clipping
CGFloat cornerRadius = 20.0;
_photoImageNode.cornerRoundingType = ASCornerRoundingTypeClipping;
_photoImageNode.backgroundColor = [UIColor whiteColor];
_photoImageNode.cornerRadius = cornerRadius;
使用 willDisplayNodeContentWithRenderingContext 設(shè)置裁剪路徑
CGFloat cornerRadius = 20.0;
// Use the screen scale for corner radius to respect content scale
CGFloat screenScale = UIScreen.mainScreen.scale;
_photoImageNode.willDisplayNodeContentWithRenderingContext = ^(CGContextRef context, id drawParameters) {
CGRect bounds = CGContextGetClipBoundingBox(context);
CGFloat radius = cornerRadius * screenScale;
UIImage *overlay = [UIImage as_resizableRoundedImageWithCornerRadius:radius
cornerColor:[UIColor clearColor]
fillColor:[UIColor clearColor]];
[overlay drawInRect:bounds];
[[UIBezierPath bezierPathWithRoundedRect:bounds cornerRadius:radius] addClip];
};
使用 ASImageNode 獲取圓形圖像并添加邊框
非常適合于獲取圓形頭像咒林。
CGFloat cornerRadius = 20.0;
_photoImageNode.imageModificationBlock = ASImageNodeRoundBorderModificationBlock(5.0, [UIColor orangeColor]);
上一篇:Texture 便捷方法
歡迎更多指正:https://github.com/pro648/tips
本文地址:https://github.com/pro648/tips/blob/master/sources/Texture%20%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96.md