Texture 基本控件 Node

這是 Texture 文檔系列翻譯,其中結合了自己的理解和工作中的使用體會。如果哪裏有誤,希望指出。

  1. Texture 核心概念

  2. Texture 佈局 Layout

  3. Texture 便捷方法

  4. Texture 性能優化

  5. Texture 容器 Node Containers

  6. Texture 基本控件 Node

  7. Texture 中 Node 的生命週期

ASDisplayNode

Node 基礎知識

ASDisplayNode是對UIViewCALayer的抽象。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 類,可用於ASTableNodeASCollectionNodeASPagerNode

三種初始化 cell 方式

有以下三種初始化ASCellNode方式:

  • 子類化ASCellNode
  • 使用已有ASViewController初始化。
  • 使用UIViewCALayer初始化。

通常需要實現以下方法:

  • init:線程安全的初始化方法。
  • layoutSpecThatFits:返回 cell 的佈局規範。
  • didLoad在主線程調用,用於添加手勢、訪問 view 的操作。
  • layout在主線程調用,調用 super 後佈局即已完成,可以進一步調整佈局。

使用ASViewControllerUIView初始化 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提供了contentVerticalAlignmentcontentHorizontalAlignment屬性,可以方便設置 button node 中的 titleLabel 和 image。

self.buttonNode.contentVerticalAlignment = ASVerticalAlignmentTop;
self.buttonNode.contentHorizontalAlignment = ASHorizontalAlignmentMiddle;

如果ASButtonNode不同狀態標題長度不同,button node 會自動拉伸、壓縮自身大小。這是因爲設置標題時,會調用setNeedsLayout

如果想要點擊 button node 後改變爲選中狀態,需要手動設置。

ASTextNode

ASTextNode是 Texture 的主要文本 node,用以替換UILabelASTextNode支持富文本,繼承自ASControlNode。也就是當只爲UIButton設置titleLabel時,也可以使用ASTextNode

基本使用

ASTextNodeUILabel類似,但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查看詳細內容。

圖像裁剪

ASImageNodecontentMode設置爲UIViewContentModeScaleAspectFill時,其會自動拉伸圖片以佔完可用空間,並裁剪掉超出區域。

默認情況下,拉伸後的圖片以 image node 中心進行佈局。以下圖爲例,貓的頭部會被裁剪掉一部分:

通過設置cropRect屬性,可以偏移圖片裁剪區域。rect 單位爲 unit rectangle,使用圖片高寬的百分比。例如,CGRectMake(0.5, 0, 0.5, 1.0)會顯示右半部分圖片。默認爲CGRectMake(0.5, 0.5, 0.0, 0.0)。如果想使圖片左對齊,可以設置cropRectx值爲0.0,也就是圖片的原點爲(0, 0)

self.animalImageNode.cropRect = CGRectMake(0, 0, 0.0, 0.0);

寬高設置爲0.0表示圖片不進行拉伸。

也可以設置x值爲1.0,以使圖像右對齊。

ASNetworkImageNode

如果要顯示遠程圖像,可以使用ASNetworkImageNode。只需爲ASNetworkImageNodeURL屬性設置 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 時不包括PINRemoteImagePINCache依賴項,則將失去對漸進式圖片( 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協議內所有方法。

ASVideoPlayerNodeASVideoNode基礎上添加了播放控件,ASVideoPlayerNode繼承自ASDisplayNode

除上面提到的 node,Texture 還提供了ASMapNodeASControlNodeASScrollNodeASEditableTextNodeASMultiplexImageNode,這裏不再繼續介紹。

上一篇:Texture 容器 Node Containers

下一篇:Texture 中 Node 的生命週期

歡迎更多指正:https://github.com/pro648/tips

本文地址:https://github.com/pro648/tips/blob/master/sources/Texture%20基本控件%20Node.md

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章