這是 Texture 文檔系列翻譯,其中結合了自己的理解和工作中的使用體會。如果哪裏有誤,希望指出。
ASDisplayNode
Node 基礎知識
ASDisplayNode
是對UIView
和CALayer
的抽象。ASDisplayNode
初始化並擁有視圖的方式與UIView
創建並擁有CALayer
的方式一致。
ASDisplayNode *node = [[ASDisplayNode alloc] init];
node.backgroundColor = [UIColor orangeColor];
node.bounds = CGRectMake(0, 0, 100, 100);
NSLog(@"Underlying view: %@", node.view);
node 擁有UIView
的所有屬性。因此,使用 node 時會發現其與UIKit
很像。
view 和 layer 的屬性均會轉發給 node,可以輕鬆訪問。
ASDisplayNode *node = [[ASDisplayNode alloc] init];
node.clipsToBounds = YES; // not .masksToBounds
node.borderColor = [UIColor blueColor]; //layer name when there is no UIView equivalent
NSLog(@"Backing layer: %@", node.layer);
從上述代碼可以看到,屬性命名規則與UIView
保持一致,除非UIView
沒有對應屬性。與處理UIView
類似,也可以操作CALayer
。
Node 使用
position
而非center
,這是唯一例外。
node 用在 node container 中時,node 所有屬性均會在後臺線程設置,並且會用該 node 收集的緩存屬性延遲構造視圖、圖層。開發者無需擔心跳轉到後臺線程,因爲 Texture 會自動處理這些問題,但有必要知道這些是在後臺線程處理的。
封裝視圖
在某些情況下,希望爲 node 初始化方法提供基於 view 的支持。view 通過 block 提供,這樣可以延遲構造。這樣創建的 node 同步繪製,因爲只有封裝的_ASDisplayView
纔可以異步繪製。
ASDisplayNode *node = [ASDisplayNode alloc] initWithViewBlock:^{
SomeView *view = [[SomeView alloc] init];
return view;
}];
通過上述方法,可以將已經存在的UIView
轉換爲ASDisplayNode
。
ASCellNode
ASCellNode
是 Texture 中的 cell 類,可用於ASTableNode
、ASCollectionNode
、ASPagerNode
。
三種初始化 cell 方式
有以下三種初始化ASCellNode
方式:
- 子類化
ASCellNode
- 使用已有
ASViewController
初始化。 - 使用
UIView
、CALayer
初始化。
通常需要實現以下方法:
-
init
:線程安全的初始化方法。 -
layoutSpecThatFits:
返回 cell 的佈局規範。 -
didLoad
在主線程調用,用於添加手勢、訪問 view 的操作。 -
layout
在主線程調用,調用 super 後佈局即已完成,可以進一步調整佈局。
使用
ASViewController
和UIView
初始化 cell 的方法在Texture 容器 Node Containers這篇文章已經講過。
ASButtonNode
基本用途
ASButtonNode
繼承自ASControlNode
,這一點與UIButton
繼承自UIControl
類似。但ASButtonNode
通過開啓 layer back 可以大幅減少主線程工作量。
Control State
如果你用過setTitle:forControlState:
,那你已經知道如何使用ASButtonNode
了。ASButtonNode
額外增加了一些屬性,方面進行自定義設置:
[buttonNode setTitle:@"Button Title Normal" withFont:nil withColor:[UIColor blueColor] forState:ASControlStateNormal];
// 可以把 title 設置爲富文本
[self.buttonNode setAttributedTitle:attributedTitle forState:ASControlStateNormal];
Target-Action 對
與UIKit
類似,可以添加 target-action 響應各種事件。
[buttonNode addTarget:self action:@selector(buttonPressed:) forControlEvents:ASControlNodeEventTouchUpInside];
Content Alignment
ASButtonNode
提供了contentVerticalAlignment
和contentHorizontalAlignment
屬性,可以方便設置 button node 中的 titleLabel 和 image。
self.buttonNode.contentVerticalAlignment = ASVerticalAlignmentTop; self.buttonNode.contentHorizontalAlignment = ASHorizontalAlignmentMiddle;
如果
ASButtonNode
不同狀態標題長度不同,button node 會自動拉伸、壓縮自身大小。這是因爲設置標題時,會調用setNeedsLayout
。如果想要點擊 button node 後改變爲選中狀態,需要手動設置。
ASTextNode
ASTextNode
是 Texture 的主要文本 node,用以替換UILabel
。ASTextNode
支持富文本,繼承自ASControlNode
。也就是當只爲UIButton
設置titleLabel
時,也可以使用ASTextNode
。
基本使用
ASTextNode
與UILabel
類似,但ASTextNode
只接受富文本。
NSDictionary *attrs = @{ NSFontAttributeName: [UIFont fontWithName:@"HelveticaNeue" size:12.0f] };
NSAttributedString *string = [[NSAttributedString alloc] initWithString:@"Hey, here's some text." attributes:attrs];
_node = [[ASTextNode alloc] init];
_node.attributedText = string;
如上所示,想要創建ASTextNode
只需 alloc、init、設置文本即可。
截斷
當要顯示內容所需區域大於提供的展示區域時,會盡可能多的展示內容,並進行截斷。使用truncationAttributedText
可以替換截斷標誌。
_textNode = [[ASTextNode alloc] init];
_textNode.attributedText = string;
_textNode.truncationAttributedText = [[NSAttributedString alloc] initWithString:@"¶¶¶"];
顯示如下:
不設置truncationAttributedText
時,使用默認截斷字符“...“。
鏈接
爲了將文本塊設置爲鏈接,首先需要設置linkAttributes
數組,該數組的元素作爲設置鏈接的 key。當設置文本屬性時,使用上述 key 標記 URL。
_textNode.linkAttributeNames = @[ kLinkAttributeName ];
NSString *blurb = @"kittens courtesy placekitten.com \U0001F638";
NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:blurb];
[string addAttribute:NSFontAttributeName value:[UIFont fontWithName:@"HelveticaNeue-Light" size:16.0f] range:NSMakeRange(0, blurb.length)];
[string addAttributes:@{
kLinkAttributeName: [NSURL URLWithString:@"http://placekitten.com/"],
NSForegroundColorAttributeName: [UIColor grayColor],
NSUnderlineStyleAttributeName: @(NSUnderlineStyleSingle | NSUnderlinePatternDot),
}
range:[blurb rangeOfString:@"placekitten.com"]];
_textNode.attributedText = string;
_textNode.userInteractionEnabled = YES;
鏈接爲淺灰色,且帶有下劃線。如下所示:
ASTextNodeDelegate
遵守ASTextNodeDelegate
協議可以對 text node 的事件進行響應。例如,對點擊 URL 進行響應:
- (void)textNode:(ASTextNode *)richTextNode tappedLinkAttribute:(NSString *)attribute value:(NSURL *)URL atPoint:(CGPoint)point textRange:(NSRange)textRange
{
// the link was tapped, open it
[[UIApplication sharedApplication] openURL:URL];
}
另外,還可以對長按、高亮進行響應:
- (void)textNode:(ASTextNode *)textNode longPressedLinkAttribute:(NSString *)attribute value:(id)value atPoint:(CGPoint)point textRange:(NSRange)textRange;
- (BOOL)textNode:(ASTextNode *)textNode shouldHighlightLinkAttribute:(NSString *)attribute value:(id)value atPoint:(CGPoint)point;
- (BOOL)textNode:(ASTextNode *)textNode shouldLongPressLinkAttribute:(NSString *)attribute value:(id)value atPoint:(CGPoint)point;
ASImageNode
ASImageNode
用以替換UIImageView
,主要區別在於ASImageNode
圖片解碼異步進行,另外也有更爲高級的改進。例如,支持 GIF 和imageModificationBlock
。
基本使用
使用 image node 和使用 image view 類似:
ASImageNode *imageNode = [[ASImageNode alloc] init];
imageNode.image = [UIImage imageNamed:@"someImage"];
imageNode.contentMode = UIViewContentModeScaleAspectFill;
圖像變換
通常,改變圖像外觀對於主線程是一項昂貴操作,因此希望將其移動到後臺線程進行。
通過爲imageNode
賦值imageModificationBlock
,可以爲圖片指定一組需要異步執行的操作。例如,圓角、邊框、圖案疊加等。
點擊修改圖像塊 Image Modification Blocks查看詳細內容。
圖像裁剪
當ASImageNode
的contentMode
設置爲UIViewContentModeScaleAspectFill
時,其會自動拉伸圖片以佔完可用空間,並裁剪掉超出區域。
默認情況下,拉伸後的圖片以 image node 中心進行佈局。以下圖爲例,貓的頭部會被裁剪掉一部分:
通過設置cropRect
屬性,可以偏移圖片裁剪區域。rect 單位爲 unit rectangle,使用圖片高寬的百分比。例如,CGRectMake(0.5, 0, 0.5, 1.0)
會顯示右半部分圖片。默認爲CGRectMake(0.5, 0.5, 0.0, 0.0)
。如果想使圖片左對齊,可以設置cropRect
的x
值爲0.0
,也就是圖片的原點爲(0, 0)
。
self.animalImageNode.cropRect = CGRectMake(0, 0, 0.0, 0.0);
寬高設置爲0.0
表示圖片不進行拉伸。
也可以設置x
值爲1.0
,以使圖像右對齊。
ASNetworkImageNode
如果要顯示遠程圖像,可以使用ASNetworkImageNode
。只需爲ASNetworkImageNode
的URL
屬性設置 URL,圖像將異步加載、顯示。ASNetworkImageNode
繼承自ASImageNode
。
ASNetworkImageNode *imageNode = [[ASNetworkImageNode alloc] init];
imageNode.URL = [NSURL URLWithString:@"https://raw.githubusercontent.com/wiki/pro648/tips/images/URLSessionPreview.png"];
佈局 ASNetworkImageNode
ASNetworkImageNode
沒有固有大小,因此需要顯式設置如何佈局ASNetworkImageNode
。
佈局方式一:style.perferredSize
如果希望將 image node 設置爲固定大小,則可以設置style.preferredSize
屬性。
- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constraint
{
imageNode.style.preferredSize = CGSizeMake(100, 200);
...
return finalLayoutSpec;
}
佈局方式二:ASRatioLayoutSpec
設置圖片高寬比例(ratio),而非固定大小進行佈局:
- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constraint
{
CGFloat ratio = 3.0/1.0;
ASRatioLayoutSpec *imageRatioSpec = [ASRatioLayoutSpec ratioLayoutSpecWithRatio:ratio child:self.imageNode];
...
return finalLayoutSpec;
}
Under the Hood
如果使用 Texture 時不包括PINRemoteImage
和PINCache
依賴項,則將失去對漸進式圖片( progressive jpeg)的支持。同時需要提供遵守ASImageCacheProtocol
協議的自定義緩存策略。
漸進式圖片 Progressive JPEG Support
因爲 Texture 依賴於PINRemoteImage
,網絡圖片支持加載 progressive JPEG。也就是說,如果服務器支持漸進式加載,則會先加載較低質量圖片,隨着其他數據到達再顯示高質量圖片。
想要啓用漸進式加載,只需將shouldRenderProgressImages
屬性設置爲YES
即可。
networkImageNode.shouldRenderProgressImages = YES;
這裏使用的是一張圖片,漸進式加載。如果服務器只支持普通 JPEG 圖片,但提供多個清晰度的版本,則應使用ASMultiplexImageNode。
自動緩存
ASNetworkImageNode
默認使用PinCache對網絡圖片進行緩存。
支持播放 GIF
ASNetworkImageNode
通過PINRemoteImage
的 beta 版PINAnimatedImage
提供 GIF 支持。除非將shouldCacheImage
屬性設置爲NO
,否則將不支持播放本地 GIF。
ASVideoNode
ASVideoNode
可以方便高效的播放視頻。
基本使用
最簡單的使用方式就是爲ASVideoNode
設置AVAsset
。
ASVideoNode *videoNode = [[ASVideoNode alloc] init];
AVAsset *asset = [AVAsset assetWithURL:[NSURL URLWithString:@"https://video-ssl.itunes.apple.com/itunes-assets/Video114/v4/3d/23/5f/3d235f2d-7f0d-716a-7d68-a1752a462d33/mzvf_8279490716204901151.640x480.h264lc.U.p.m4v"]];
videoNode.asset = asset;
自動播放 循環播放 靜音
通過設置簡單的BOOL
值,可以實現自動播放、循環播放和靜音。
如果想要視頻進入可見狀態時自動播放,將shouldAutoplay
設置爲YES
即可;將shouldAutoRepeat
設置爲YES
視頻將循環播放;將muted
設置爲YES
視頻將自動靜音。
視頻自動、靜音、循環播放設置如下:
videoNode.shouldAutoplay = YES;
videoNode.shouldAutorepeat = YES;
videoNode.muted = YES;
佔位圖
ASVideoNode
繼承自ASNetworkImageNode
,可以通過URL
屬性添加佔位圖。如果不設置佔位圖,會自動解碼視頻的第一幀並設置爲佔位圖。
ASVideoNodeDelegate
ASVideoNodeDelegate
協議提供了視頻狀態變化。該協議內所有方法均爲可選實現。如果想要在視頻播放完畢時作出響應:
- (void)videoDidPlayToEnd:(ASVideoNode *)videoNode;
在
ASVideoNode.h
文件可以查看ASVideoNodeDelegate
協議內所有方法。
ASVideoPlayerNode
在ASVideoNode
基礎上添加了播放控件,ASVideoPlayerNode
繼承自ASDisplayNode
。
除上面提到的 node,Texture 還提供了ASMapNode、ASControlNode、ASScrollNode、ASEditableTextNode、ASMultiplexImageNode,這裏不再繼續介紹。
歡迎更多指正:https://github.com/pro648/tips
本文地址:https://github.com/pro648/tips/blob/master/sources/Texture%20基本控件%20Node.md