AsyncDisplayKit入門指南

非死book前兩天發布了其iOS UI框架AsyncDisplayKit(ASDK)的1.0正式版,這個框架被用于非死book自家的應用Paper,能夠提高UI的流暢性并縮短響應時間。
下載和使用
你可以使用CocoaPods來安裝AsyncDisplayKit,在Podfile中添加:
pod 'AsyncDisplayKit'
OC中導入框架header,如果用Swift則可以創建Objective-C bridging header:
#import <AsyncDisplayKit/AsyncDisplayKit.h>
概述
AsyncDisplayKit(ASDK)的基本單元是node,ASDisplayNode是UIView之上的抽象層,因此同時也是 CALayer的抽象層。和只能被用在主線程的視圖不同,nodes是線程安全的:你能并行的實例化并設置整個node層級,并且在后臺線程里運行。
為了保證它的用戶界面的流暢和響應,你的app渲染幀率應該和iOS基準保持同步,即60幀每秒。這意味著主線程對每一幀有60分之一的時間來推送,這大約是16毫秒,需要在如此短時間內來執行所有的布局和繪制的代碼。而由于系統的性能開銷,在導致丟幀之前,你的代碼通常只有不到10毫秒的時間來執行。
AsyncDisplayKit讓你將圖像解碼、調整文字大小并渲染,以及其他高耗時的UI操作移出主線程。當然它還有其他的一些功能,你可以在官方文檔中探索。
作為視圖直接替代的Node
如果你之前處理過視圖,那么你已經知道如何使用node了。Node的API也類似于UIView,不過更方便。比如,你能直接讀取公共的CALayer屬性。添加一個node到現有的視圖或層級,使用node.view或node.layer。
AsyncDisplayKit包括一些強力的組件:
- ASDisplayNode. UIView的副本 — 一個子類,用來自定義node。
- ASControlNode. 類似于UIControl — 用來制作按鈕的子類。
- ASImageNode. 類似于UIImageView — 異步的解碼圖像資源。
- ASTextNode. 類似于UITextView — 基于TextKit構建,支持富文本的全部特性。
- ASTableView. UITableView子類,用于支持node。
你可以將這些用作UIKit副本的直接替代。即便ASDK在完整的基于node的層級下工作十分高效,使用node替代獨立視圖能夠更加的提高性能。
讓我們來看一個例子。
我們一開始在主線程中異步的使用node——和你平常使用視圖的方式一樣。我們的代碼和自定義視圖控制器-loadView的實現差不多:
_imageView = [[UIImageView alloc] init]; _imageView.image = [UIImage imageNamed:@"hello"]; _imageView.frame = CGRectMake(10.0f, 10.0f, 40.0f, 40.0f); [self.view addSubview:_imageView];
我們能使用如下基于node的代碼來替代它:
_imageNode = [[ASImageNode alloc] init]; _imageNode.backgroundColor = [UIColor lightGrayColor]; _imageNode.image = [UIImage imageNamed:@"hello"]; _imageNode.frame = CGRectMake(10.0f, 10.0f, 40.0f, 40.0f); [self.view addSubview:_imageNode.view];
這并沒有利用ASDK的異步調整大小和布局的功能,但已經有所改進了。第一段代碼在主線程解碼hello.png,第二段則在后臺線程解碼圖像,并可能利用不同的CPU核心。
(注意我們在node中設置了占位符的背景顏色,它會占據屏幕直到真正的內容出現。這種做法對于圖像很好,但不太適用于文字——人們期望文字能直接展示,圖片則允許有加載延遲。我們后面會討論如何改進的技術。)
node按鈕
ASImageNode和ASTextNode都繼承了ASControlNode,所以你能將它們當做按鈕使用。假設我們在開發音樂播放器,并且希望添加(非擬物化的,iOS 7風格)隨機播放按鈕。
我們的視圖控制器代碼將和下面的差不多:
- (void)viewDidLoad
{
[super viewDidLoad];
// attribute a string
NSDictionary *attrs = @{
NSFontAttributeName: [UIFont systemFontOfSize:12.0f],
NSForegroundColorAttributeName: [UIColor redColor],
};
NSAttributedString *string = [[NSAttributedString alloc] initWithString:@"shuffle"
attributes:attrs];
// create the node
_shuffleNode = [[ASTextNode alloc] init];
_shuffleNode.attributedString = string;
// configure the button
_shuffleNode.userInteractionEnabled = YES; // opt into touch handling
[_shuffleNode addTarget:self
action:@selector(buttonTapped:)
forControlEvents:ASControlNodeEventTouchUpInside];
// size all the things
CGRect b = self.view.bounds; // convenience
CGSize size = [_shuffleNode measure:CGSizeMake(b.size.width, FLT_MAX)];
CGPoint origin = CGPointMake(roundf( (b.size.width - size.width) / 2.0f ),
roundf( (b.size.height - size.height) / 2.0f ));
_shuffleNode.frame = (CGRect){ origin, size };
// add to our view
[self.view addSubview:_shuffleNode.view];
}
- (void)buttonTapped:(id)sender
{
NSLog(@"tapped!");
} 這段代碼能正常工作。不幸的是,這個按鈕只有14?個像素點高,離標準的44×44最小點擊尺寸相距甚遠,因此很難點擊到。我們能夠通過為 text node創建子類,并且覆蓋-hitTest:withEvent:來解決這個問題。我們甚至能強制text view在布局中的最低高度,但如果有更優雅的解決辦法不是更好嗎?
// size all the things /* ... */ // make the tap target taller CGFloat extendY = roundf( (44.0f - size.height) / 2.0f ); _shuffleNode.hitTestSlop = UIEdgeInsetsMake(-extendY, 0.0f, -extendY, 0.0f);
就是這樣!Hit-test slops在所有node中都能正常工作,并且是一個展示這個新的抽象層能干什么的極好的示例。
后面還會講如何自定義node、異步的工作方式、最大限度的利用AsyncDisplayKit等,感興趣的可以查看官方文檔。
來自:http://idlelife.org/archives/733