ASDK的使用(一)

在這個(gè)AsyncDisplayKit 2.0教程中厢洞,學(xué)習(xí)如何通過(guò)異步渲染的強(qiáng)大功能使用戶界面及其流暢的滾動(dòng)元潘。

paper

AsyncDisplayKit是最初由Facebook的Paper應(yīng)用程序開(kāi)發(fā)的UI框架穿撮。這就是Paper團(tuán)隊(duì)面臨的核心問(wèn)題之一:如何盡可能緩解主線程的壓力鹃彻?

現(xiàn)在,許多應(yīng)用程序的用戶體驗(yàn)很大程度上依賴于持續(xù)手勢(shì)和物理動(dòng)畫(huà)熙暴。至少,你的UI大部分依賴于某種形式的 scrollView

這些類型的用戶界面完全依賴于主線程且對(duì)主線程阻塞非常敏感秒咨。主線程阻塞將導(dǎo)致丟幀,降低用戶的體驗(yàn)计呈。

主線程開(kāi)銷較大的任務(wù)一般分為:

  • 1: 計(jì)算尺寸和布局:比如 -heightForRowAtIndexPath:砰诵,或者在UILbel中調(diào)用 -sizeThatFits以及指數(shù)上升AutoLayout布局計(jì)算
  • 2: 圖像解碼:想要在一個(gè) imageView 中使用 UIImage,首先要進(jìn)行圖形解碼捌显。
  • 3: 繪圖:復(fù)雜的文本以及手動(dòng)繪制漸變和陰影胧砰。
  • 4: 對(duì)象生命周期:創(chuàng)建,操縱和銷毀系統(tǒng)對(duì)象(即創(chuàng)建一個(gè)UIView)

在正確使用中, AsyncDisplayKit允許您在默認(rèn)情況下異步執(zhí)行所有計(jì)算苇瓣、布局和渲染尉间。在沒(méi)有任何額外優(yōu)化的情況下,應(yīng)用程序可以在主線程上完成的工作量大約減少一個(gè)數(shù)量級(jí)

除了這些性能優(yōu)勢(shì)击罪,酷炫的 AsyncDisplayKit 還為開(kāi)發(fā)者提供的便利接口哲嘲,用簡(jiǎn)潔的代碼就能完成復(fù)雜的功能。

在這兩部分 AsyncDisplayKit 2.0 教程中媳禁,你將掌握使用ASDK構(gòu)建一個(gè)實(shí)用的和動(dòng)態(tài)的應(yīng)用程序的所有要素眠副。 在第一部分中,你將要學(xué)習(xí)一些在你構(gòu)建應(yīng)用程序時(shí)可以用到的宏觀思想竣稽。 在第二部分中囱怕,你將學(xué)習(xí)如何構(gòu)建自己 nodesubclass霍弹,以及如何使用ASDK強(qiáng)大的布局引擎。為了更好的完成本教程娃弓,你需要會(huì)使用 Xcode 以及 熟悉 Objective-C典格。

特別聲明:ASDK不兼容Interface Builder和AutoLayout,因此台丛,您將不會(huì)在本教程中使用它們耍缴,雖然ASDK完全支持Swift(除了ComponentKit),許多開(kāi)發(fā)者仍在使用.
Objective-C挽霉。免費(fèi)App排行榜前100大多數(shù)都沒(méi)有使用Swift(至少6個(gè)使用ASDK)防嗡。出于這些原因,本系列將重點(diǎn)介紹 Objective-C侠坎。話雖這么說(shuō)蚁趁,我們已經(jīng)包括了一個(gè)Swift版本的實(shí)例項(xiàng)目。(嘴上說(shuō)沒(méi)有实胸,代碼還是很誠(chéng)實(shí)的??~)

一: 開(kāi)始

請(qǐng)下載項(xiàng)目實(shí)例

該項(xiàng)目使用CocoaPods來(lái)拉入AsyncDisplayKit荣德。 因此,所以童芹,在正常的 CocoaPods 體系下,繼續(xù)打開(kāi)RainforestStarter.xcworkspace而不是RainforestStarter.xcodeproj鲤拿。

構(gòu)建并運(yùn)行以查看包含 UITableView 動(dòng)物列表的應(yīng)用程序假褪。如果你看過(guò)了代碼,AnimalTableController你會(huì)發(fā)現(xiàn)這是一個(gè)正常且熟悉的UITableViewController類近顷。

注意:確保在真機(jī)上運(yùn)行本教程中的代碼生音,而不是在模擬器中運(yùn)行。

向上滑動(dòng)你將看到幀數(shù)丟失引起的卡頓窒升。你不需要啟動(dòng)控制臺(tái)缀遍,以便能發(fā)現(xiàn)到這個(gè)應(yīng)用程序需要在性能方面上的一些優(yōu)化。

[圖片上傳失敗...(image-c8c6db-1547448512256)]

您可以通過(guò)AsyncDisplayKit的強(qiáng)大功能來(lái)解決這個(gè)問(wèn)題饱须。

二: 介紹ASDisplayNode

ASDisplayNode是ASDK的核心類域醇,它只是一個(gè)類似于 MVC 中的 “View”。認(rèn)識(shí)一個(gè) node 的最佳方法是參照你已經(jīng)熟悉的UIViewsCALayers 之間的關(guān)系蓉媳。

記住譬挚,iOS應(yīng)用程序中的所有在屏幕上的顯示都通過(guò)CALayer對(duì)象表示的。UIViews 創(chuàng)建并且擁有一個(gè)底層的 CALayer酪呻,并為他們添加觸摸處理和其他交互功能减宣。UIView 并不是 CALayer 的子類,它們環(huán)繞著一個(gè)圖層對(duì)象玩荠,擴(kuò)展了它的功能.

image

這種抽象的情況下擴(kuò)展 ASDisplayNode 您可以將它們視為包裝一個(gè)view漆腌,就像在 view 包裝著layer 一樣贼邓。

通過(guò)常規(guī)視圖將哪些節(jié)點(diǎn)帶到表中的事實(shí)是它們可以在后臺(tái)隊(duì)列上創(chuàng)建和配置,并且默認(rèn)情況下同時(shí)呈現(xiàn)


image

幸運(yùn)的是闷尿,用于處理 Node 的 API 對(duì)于任何使用過(guò)的 UIViews 或者 CALayers 的人來(lái)說(shuō)應(yīng)該異常的熟悉塑径。所有 View 的屬性都可以等效為 Node 類。你可以訪問(wèn)基礎(chǔ)的 view 或者 layer 本身悠砚,就像是訪問(wèn) view.layer 一樣

三: 節(jié)點(diǎn)容器(The Node Containers)

雖然 Node 本身提供了巨大的性能改進(jìn)的可能晓勇,但真正的強(qiáng)大的是它們與四個(gè)容器類結(jié)合使用時(shí)產(chǎn)生的黑魔法。

這些類包括:
-ASViewController:一個(gè)UIViewController的子類灌旧,允許你提供要管理的 Node绑咱。
-ASCollectionNodeASTableNode:與UICollectionViewUITableView的等價(jià),其子類實(shí)際上保留在底層枢泰。

  • ASCollectionNodeASTableNode:與UICollectionViewUITableView的等價(jià)描融,其子類實(shí)際上是在框架維護(hù)的。

  • ASPagerNodeASCollectionNode的一個(gè)子類衡蚂,與UIKit的UIPageViewController相比窿克,可以提供很好的刷卡性能。

說(shuō)得好毛甲,但真正的黑魔法來(lái)自ASRangeController 這些類用于影響所包含的 Node 的行為∧甓#現(xiàn)在,跟著我并把你們的腦袋放空吧~

四: TableNode

你要做的第一件事就是將當(dāng)前 TableView 替換為 TableNode玻募。這個(gè)沒(méi)什么難度只损。

4.1: tableNode來(lái)替換tableView

首先,導(dǎo)航到AnimalTableController.m七咧。 在該類的其他導(dǎo)入下方添加以下行:

#import <AsyncDisplayKit/AsyncDisplayKit.h>

導(dǎo)入ASDK為了使用框架跃惫。
然后,我們繼續(xù)艾栋,替換 tableView 的聲明屬性 :

@property (strong, nonatomic) ASTableNode *tableNode;

來(lái)替換

@property (strong, nonatomic) UITableView *tableView;

這將導(dǎo)致這個(gè)類中很多地方報(bào)錯(cuò)朽褪,但不要慌張阅懦!

別擔(dān)心诉探。這些錯(cuò)誤和警告將作為你實(shí)現(xiàn)相關(guān)功能的引導(dǎo)掏击。

-viewDidLoad 中的報(bào)錯(cuò)是理所當(dāng)然,因?yàn)?tableView 已經(jīng)被替換掉悼粮。我不會(huì)讓你通過(guò)tableNode 替換 所有的tableView實(shí)例(我的意思是拇泣,查找和替換并非那么難),但是如果你做了矮锈,你會(huì)看到:

  • 1: 你應(yīng)該為ASTableNode分配一個(gè)屬性霉翔。
  • 2: table Node 沒(méi)有調(diào)用 -registerClass:forCellReuseIdentifier: 方法。
  • 3: 你不能添加一個(gè) nodesubview

此時(shí)苞笨,你應(yīng)該將 -viewDidLoad 中的方法替換為:

- (void)viewDidLoad {
  [super viewDidLoad];
  [self.view addSubnode:self.tableNode];
  [self applyStyle];
}

這里要注意一個(gè)有趣的情況债朵,你調(diào)用的是 UIView的一個(gè) -addSubnode: 方法子眶,該方法是通過(guò) category 添加到 UIView 上的,等效于:

[self.view addSubview:self.tableNode.view];

接下來(lái)序芦,修改 -viewWillLayoutSubviews 中的代碼:

- (void)viewWillLayoutSubviews {
  [super viewWillLayoutSubviews];
  self.tableNode.frame = self.view.bounds;
}

所有這一切都是用self.tableNode替換self.tableView來(lái)設(shè)置表的框架臭杰。

繼續(xù)修改 -applyStyle 方法中的代碼為:

- (void)applyStyle {
  self.view.backgroundColor = [UIColor blackColor];
  self.tableNode.view.separatorStyle = UITableViewCellSeparatorStyleNone;
}

這是唯一設(shè)置 tableseparatorStyle 的一行代碼。注意 tableNodeview 是如何訪問(wèn) tableseparatorStyle 屬性的谚中。ASTableNode 不會(huì)暴露所有UITableView的的屬性渴杆,所以你必須通過(guò)tableNode底層的 UITableView 實(shí)例去設(shè)置 UITableView 的特殊屬性。

然后宪塔,在 -initWithAnimals: 方法中添加磁奖。

_tableNode = [[ASTableNode alloc] initWithStyle:UITableViewStylePlain];

并且在 return 之前,調(diào)用:

[self wireDelegation];

這就會(huì)在初始化 AnimalTableController 的時(shí)候某筐,創(chuàng)建了一個(gè) tableNode 并且調(diào)用 -wireDelegation 方法 設(shè)置 tableNode 的 代理比搭。

4.2: 設(shè)置 TableNode 的 DataSource & Delegate

類似于 UITableViewASTableNode 也使用 DataSourceDelegate 來(lái)設(shè)置本身南誊。TableNodeASTableDataSourceASTableDelegate protocols 非常類似于 UITableViewDataSourceUITableViewDelegate身诺。

事實(shí)上,雖然他們定義了一些完全相同的方法抄囚,如 -tableNode:numberOfRowsInSection:霉赡,但兩組協(xié)議也不完全相同,因?yàn)?ASTableNode 行為和 UITableView 還以所有不同的幔托。

找到 -wireDelegation 方法穴亏, 并用 tableNode 替換 tableView

- (void)wireDelegation {
  self.tableNode.dataSource = self;
  self.tableNode.delegate = self;
}

現(xiàn)在, 你會(huì)收到警告, AnimalTableController 實(shí)際上不符合協(xié)議柑司。目前,AnimalTableController 僅遵循 UITableViewDataSourceUITableViewDelegate 協(xié)議锅劝。在下面的章節(jié)中攒驰,我們將遵循這些協(xié)議,使我們能夠使用 tableNode 的功能故爵。

4.3: 遵循 ASTableDataSource

AnimalTableController.m 開(kāi)頭的地方找到 AnimalTableControllerDataSource 擴(kuò)展聲明:

@interface AnimalTableController (DataSource)<UITableViewDataSource>
@end

ASTableDataSource 替換 UITableViewDataSource為:

@interface AnimalTableController (DataSource)<ASTableDataSource>
@end

現(xiàn)在玻粪,AnimalTableController 已經(jīng)遵循了 AnimalTableController 協(xié)議。本就該如此了诬垂。

導(dǎo)航到 AnimalTableController.m 的底部并找到 DataSource category 的實(shí)現(xiàn)劲室。

首先,將 UITableViewDataSource-tableView:numberOfRowsInSection:方法结窘,
更改為 ASTableDataSource 的版本很洋。

- (NSInteger)tableNode:(ASTableNode *)tableNode numberOfRowsInSection:(NSInteger)section {
  return self.animals.count;
}

接著, ASTableNodescells 會(huì)以不同于 UITableView 的方式返回隧枫。用下面的代碼替換 -tableView:cellForRowAtIndexPath: 以適應(yīng)新的規(guī)則喉磁。

// 1
- (ASCellNodeBlock)tableNode:(ASTableView *)tableView nodeBlockForRowAtIndexPath:(NSIndexPath *)indexPath {
  
  // 2
  RainforestCardInfo *animal = self.animals[indexPath.row];
 
  // 3 return ASCellNodeBlock
  return ^{
    // 4
    CardNode *cardNode = [[CardNode alloc] initWithAnimal:animal];
 
    //You'll add something extra here later...
    return cardNode;
  };
}

讓我們回顧一下:

  • 1: ASDK 中的 ASCellNode 等價(jià)于 UITableViewCell 或者 UICollectionViewCell 谓苟。要注意的是這個(gè)方法返回的是一個(gè) ASCellNodeBlockASTableNode 維持著內(nèi)部所有的 Cell协怒,每個(gè) indexPath 對(duì)應(yīng)一個(gè) block涝焙,并且隨時(shí)準(zhǔn)備進(jìn)行初始化。
  • 2: 你的首要任務(wù)是通過(guò)數(shù)據(jù)模型構(gòu)建cell孕暇。這是非常重要的一步仑撞,要注意!你獲取數(shù)據(jù)后在 下面的 block 處理妖滔。不要在 block 里引用indexPath,以防止 block 運(yùn)行前的數(shù)據(jù)變動(dòng)隧哮。
  • 3: 然后返回一個(gè) block,其返回值必須為 ASCellNode
  • 4: 沒(méi)有必要擔(dān)心Cell的復(fù)用以及初始化一個(gè)Cell的方法铛楣。您可能會(huì)注意到您現(xiàn)在返回了CardNode近迁,而不是 CardCell

這讓我想到一個(gè)重要的點(diǎn)簸州〖撸或許你已經(jīng)了解到,使用 ASDK 不需要復(fù)用 cell岸浑,好吧搏存,我已經(jīng)說(shuō)了兩遍了,但能記住就好矢洲。請(qǐng)隨意刪除頂部kCellReuseIdentifier的定義吧

static NSString *kCellReuseIdentifier = @"CellReuseIdentifier";

你不必再擔(dān)心 -prepareForReuse

4.3: 遵循 ASTableDelegate

AnimalTableController.m 頂部璧眠,找到以下Delegate類別接口聲明:

@interface AnimalTableController (Delegate)<UITableViewDelegate>
@end

ASTableDelegate 替換 UITableViewDelegate

@interface AnimalTableController (Delegate)<ASTableDelegate>
@end

現(xiàn)在 AnimalTableController 已經(jīng)遵循了 ASTableDelegate,是時(shí)候做處理了读虏。在 AnimalTableController.m 底部找到 Delegate 分類的實(shí)現(xiàn)责静。

我們都知道,每個(gè) UITableView 至少都要提供一個(gè) -tableView:heightForRowAtIndexPath:實(shí)現(xiàn)方法盖桥,因?yàn)槊總€(gè) cell 的高度都由代理計(jì)算和返回灾螃。

ASTableDelegate 中沒(méi)有 -tableView:heightForRowAtIndexPath:。再 ASDK 中揩徊,所有的 ASCellNode 都負(fù)責(zé)確定自己的大小腰鬼。你可以選擇為單元格定義最小和最大尺寸,而不是提供靜態(tài)高度塑荒。這種情況下熄赡,你希望每個(gè)cell的高度至少為屏幕的 2/3。

現(xiàn)在不用擔(dān)心太多齿税,這個(gè)會(huì)在第二部分中介紹彼硫。

現(xiàn)在只需要替換 -tableView:heightForRowAtIndexPath:為:

- (ASSizeRange)tableView:(ASTableView *)tableNode 
  constrainedSizeForRowAtIndexPath:(NSIndexPath *)indexPath {
  CGFloat width = [UIScreen mainScreen].bounds.size.width;
  CGSize min = CGSizeMake(width, ([UIScreen mainScreen].bounds.size.height/3) * 2);
  CGSize max = CGSizeMake(width, INFINITY);
  return ASSizeRangeMake(min, max);
}

經(jīng)過(guò)我們的辛勤勞動(dòng),重新編譯、運(yùn)行項(xiàng)目乌助,看看發(fā)生了什么溜在。
真是一個(gè)流暢的 tableView!一旦你開(kāi)始做了他托,那就讓我們做的更好吧掖肋!

五: 無(wú)限滾動(dòng)

在大多數(shù)應(yīng)用中,服務(wù)器的數(shù)據(jù)個(gè)數(shù)往往會(huì)多于當(dāng)前 tableView 中顯示的數(shù)量赏参。這意味著志笼,你必須通過(guò)某些手段做無(wú)縫處理,以便用戶刷完當(dāng)前數(shù)據(jù)列表時(shí)從服務(wù)端加載新的數(shù)據(jù)把篓。

很多時(shí)候纫溃,這是通過(guò)手動(dòng)觀察滾動(dòng)視圖方法中的內(nèi)容偏移來(lái)處理 scrollViewDidScroll:, 使用 ASDK, 有一種更具說(shuō)明性的處理方式韧掩。相反的紊浩,你可以預(yù)先確定好你需要加載的頁(yè)數(shù)。

你要做的第一件事是取消已經(jīng)存在的方法的注釋疗锐。在 AnimalTableController.m的結(jié)尾坊谁,取消 Helpers 分類中的兩個(gè)方法。你可以認(rèn)為 -retrieveNextPageWithCompletion: 是你的網(wǎng)絡(luò)調(diào)用滑臊,而 -insertNewRowsInTableNode: 是個(gè)非常典型的再表中添加新的元素的方法口芍。

接下來(lái),在 -viewDidLoad 添加:

self.tableNode.view.leadingScreensForBatching = 1.0;  // overriding default of 2.0

設(shè)置 leadingScreensForBatching 為 1.0 意味著當(dāng)用戶滑動(dòng)到列表只剩下一個(gè)屏幕的數(shù)據(jù)的到達(dá)結(jié)尾的時(shí)候雇卷,就會(huì)載入新的數(shù)據(jù)鬓椭。

繼續(xù),在 Delegate 分類中實(shí)現(xiàn):

- (BOOL)shouldBatchFetchForTableNode:(ASTableNode *)tableNode {
  return YES;
}

此方法用于告知表是否應(yīng)該在此之后繼續(xù)請(qǐng)求新批次关划。如果您知道自己已經(jīng)到達(dá)API數(shù)據(jù)的末尾小染,請(qǐng)返回NO,不再發(fā)出請(qǐng)求贮折。

因?yàn)槟阆M麩o(wú)限滾動(dòng)裤翩,那就返回 YES,以確蓖鸦酰總是請(qǐng)求新的數(shù)據(jù)岛都。

接下來(lái)律姨,還要添加:

- (void)tableNode:(ASTableNode *)tableNode willBeginBatchFetchWithContext:(ASBatchContext *)context {
  //1
  [self retrieveNextPageWithCompletion:^(NSArray *animals) {
    //2
    [self insertNewRowsInTableNode:animals];
    //3
    [context completeBatchFetching:YES];
  }];
}

該方法在用戶滑動(dòng)到 table 的末端并且 -shouldBatchFetchForTableNode: 方法返回 YES 時(shí)被調(diào)用振峻。

讓我們回顧下上面的章節(jié):

  • 1: 首先,你要請(qǐng)求新的 animals 數(shù)據(jù)來(lái)展示择份。通常是通過(guò) API 來(lái)獲取的一組array扣孟。
  • 2: 完成后,用新下載的數(shù)據(jù)更新 tableView
  • 3: 最后荣赶,確保 -completeBatchFetching:返回的是YES凤价,即大功告成鸽斟。在完成操作之前,不會(huì)進(jìn)行新的數(shù)據(jù)請(qǐng)求利诺。

Build and Run富蓄,并且不停的滾呀滾。你將會(huì)看到不停的看到一只鳥(niǎo)慢逾,他們是無(wú)限的立倍。


2Gif.gif

六: 智能預(yù)加載

你在工作中是否曾經(jīng)遇到需要預(yù)先加載內(nèi)容到 scrollView 或者 pageView 控制器中?也許你正在處理一個(gè)充滿屏幕 image 侣滩,并且總是希望在接下來(lái)的幾張圖片加載時(shí)處于等待狀態(tài)口注,所以用戶很少看到占位符。

當(dāng)你再這樣的體系下工作時(shí)君珠,你很快就會(huì)意識(shí)到有很多問(wèn)題要考慮寝志。

  • 1: 你占用了多少內(nèi)存
  • 2: 你應(yīng)該提前多久加載內(nèi)容
  • 3: 你決定什么時(shí)候忽略用戶的交互反映

并且當(dāng)你考慮到多個(gè)維度的內(nèi)容時(shí),將些問(wèn)題將會(huì)變得更加復(fù)雜策添。假設(shè)你有一個(gè)pageViewController材部,里面每個(gè) viewController 都帶有一個(gè) collectionView。現(xiàn)在舰攒,你就需要考慮如何在兩個(gè)方向上動(dòng)態(tài)加載內(nèi)容败富。同時(shí),還要對(duì)每個(gè)設(shè)備進(jìn)行優(yōu)化摩窃。

image

還記得告訴你 ASRangeController 是不重要的嗎兽叮?現(xiàn)在,這將是我們的重點(diǎn)猾愿。

在每個(gè)容器類中鹦聪,所有包含的 node 都有一個(gè)接口狀態(tài)的概念。在任何給定的時(shí)間蒂秘,一個(gè) node 可以是下面的任意組合:


image
  • Preload Range(預(yù)載范圍):通常最遠(yuǎn)的范圍從可見(jiàn)區(qū)域泽本。這是當(dāng)cell的每個(gè) subNode (例如ASNetworkImageNode) 的內(nèi)容從外源加載,例如API和本地緩存姻僧。這與批量獲取時(shí)规丽,使用用模型對(duì)象代表cell本身形成對(duì)比。
  • Display Range(顯示范圍):在這里進(jìn)行顯示任務(wù)撇贺,例如文本繪制和進(jìn)行圖像解碼赌莺。
  • Visible Range(可見(jiàn)范圍):此時(shí),node 至少有一個(gè)像素在屏幕上松嘶。

這些范圍也適用于 screenfuls 的度量艘狭,并且可以使用 ASRangeTuningParameters 屬性輕松調(diào)整。

例如:你正在使用一個(gè) ASNetworkImageNode 在 gallery 的每個(gè)頁(yè)面中展示圖像,當(dāng)每個(gè)cell進(jìn)入 Preload Range 時(shí)巢音,會(huì)發(fā)送網(wǎng)絡(luò)請(qǐng)求遵倦,對(duì)進(jìn)入顯示范圍時(shí)檢索到的圖像進(jìn)行解碼.

一般來(lái)說(shuō),如果你不愿意官撼,你不必過(guò)多考慮這些范圍梧躺。內(nèi)置組件(如ASNetworkImageNodeASTextNode)充分利用它們,這意味著默認(rèn)情況下您將看到巨大的好處

注意: 有件不明顯的事傲绣,這些 Ranges 不是堆棧的燥狰。相反,它們會(huì)在
Visible Range 上重疊和匯聚斜筐。如果將顯示和預(yù)取都設(shè)置為一個(gè)屏幕龙致,則它們將完全相同。通常數(shù)據(jù)需要存在才能顯示顷链,所以一般預(yù)取范圍應(yīng)該稍大一點(diǎn)目代。那么在 node 到達(dá)該范圍時(shí),就可以開(kāi)始顯示嗤练。

通常榛了,該范圍的前側(cè)大于后側(cè)。當(dāng)用戶改變他們的滾動(dòng)方向時(shí)煞抬,范圍的大小也反轉(zhuǎn)霜大,以便有利于用戶實(shí)際移動(dòng)的內(nèi)容。

七: Node接口的狀態(tài)回調(diào)

你可能會(huì)疑惑:這些 Ranges 是如何正確工作的革答?很高興你這樣問(wèn)~

系統(tǒng)中的每個(gè) node 都有一個(gè) interfaceState 屬性战坤,是一個(gè)帶有字段((NS_OPTION)ASInterfaceState類型。 ASRangeController 負(fù)責(zé)管理 ASCellNodescrolView 上的移動(dòng)残拐,每個(gè) subNode 都由一個(gè) interfaceState 屬性做對(duì)應(yīng)的更新途茫。這意味著即使時(shí) tree 中最深的 nodes 也可以相應(yīng) interfaceState 的變化。

幸運(yùn)的是溪食,我們很少需要直接去操作 nodeinterfaceState 上的 二進(jìn)制位囊卜。更常見(jiàn)的做法時(shí),你只需要對(duì)某 node 的特定的狀態(tài)進(jìn)行更改错沃。這就是接口的狀態(tài)回調(diào)栅组。

7.1: Node 命名

為了看到一個(gè) node 的各種狀態(tài),給它命名時(shí)很有必要的枢析。這樣玉掸,你就可以監(jiān)測(cè)每個(gè) node 的數(shù)據(jù)加載、內(nèi)容成登疗、屏幕展示以及所以的事情排截。

回到代碼 -tableNode:nodeBlockForRowAtIndexPath:,添加一句注釋

//You'll add something extra here later...

在它的下面,給 cardNode 添加一個(gè) debugName:

cardNode.debugName = [NSString stringWithFormat:@"cell %zd", indexPath.row];

現(xiàn)在辐益,您將能夠跟蹤cell在范圍內(nèi)的進(jìn)展断傲。

7.2: 監(jiān)聽(tīng)Cells

進(jìn)入 CardNode_InterfaceCallbacks.m 中,你可以找到六種追蹤 noderanges 中的狀態(tài)的方法智政。取消注釋认罩,Build and Run。打開(kāi)你的控制臺(tái)续捂,然后慢慢滑動(dòng) table垦垂。對(duì)照你的滑動(dòng),觀察cell在對(duì)應(yīng)的狀態(tài)變化牙瓢。

201901140549031547459343377_small.gif

注意: 大多數(shù)情況下劫拗,你只要關(guān)心 -didEnterVisibleState-didExitVisibleState 方法對(duì) ASInterfaceState 的改變》耍或者說(shuō)页慷,已經(jīng)為你做好了許多引擎。你可以查看 ASNetworkImageNode 中的代碼胁附,看看你集成的通過(guò) PreloadDisplay 狀態(tài)實(shí)現(xiàn)的功能酒繁。 所有 node 網(wǎng)絡(luò)圖片的請(qǐng)求和解碼,以及內(nèi)存的釋放都是自動(dòng)完成控妻,不費(fèi)吹灰之力州袒。

八: 智能預(yù)加載(續(xù))

在 2.0 版本中,已經(jīng)介紹了多個(gè)維度上智能與加載的概念弓候。假設(shè)你有一個(gè)豎直滾動(dòng)的tableView郎哭,在其中某些Cell包含了水平滾動(dòng)的 collectionView

proaldGif.gif

雖然這個(gè)集合現(xiàn)在在技術(shù)上處于可見(jiàn)區(qū)域,但您不希望預(yù)先加載整個(gè)集合菇存。相反彰居,兩個(gè)滾動(dòng)視圖都有自己的ASRangeController,并帶有可單獨(dú)配置的范圍調(diào)整參數(shù)撰筷。

8.1: 來(lái)到二次元

現(xiàn)在陈惰,你已經(jīng)有了完整的 AnimalTableController , 你可以把它做為 ASPagerNode 的一個(gè)page。

項(xiàng)目已經(jīng)提前寫(xiě)好了控制器的代碼毕籽,首先進(jìn)入 AppDelegate.m

找到 -installRootViewController 的下面代碼:

AnimalTableController *vc = [[AnimalTableController alloc] 
                              initWithAnimals:[RainforestCardInfo allAnimals]];

替換為:

AnimalPagerController *vc = [[AnimalPagerController alloc] init];

然后抬闯,跳到 AnimalPagerController.m-init 方法中添加創(chuàng)建 pager 方法以及 dataSource 的數(shù)據(jù)源:

_pagerNode = [[ASPagerNode alloc] init];
_pagerNode.dataSource = self;

pagerNode 是 ASCollectionNode 的子類,使用方法與 UIPageViewController 一樣关筒。API 實(shí)際上比 UIPageViewController 要簡(jiǎn)單的多溶握。

接下來(lái)要實(shí)現(xiàn) pager 的 dataSource 方法,在底部找到 ASPagerDataSource 分類.

首先蒸播,告訴 pager 有幾個(gè)頁(yè)面睡榆。實(shí)際上當(dāng)前的 animal 數(shù)組中有三組不同動(dòng)物萍肆,我們需要重寫(xiě) -numberOfPagesInPagerNode:方法:

- (NSInteger)numberOfPagesInPagerNode:(ASPagerNode *)pagerNode {
  return self.animals.count;
}

然后,你需要實(shí)現(xiàn) -pagerNode:nodeAtIndex 方法胀屿,類似于先前實(shí)現(xiàn)的 ASTableNodedataSource 方法塘揣。

- (ASCellNode *)pagerNode:(ASPagerNode *)pagerNode nodeAtIndex:(NSInteger)index {
    // 1
    NSArray *animals = self.animals[index];
    // 2
    ASCellNode *node = [[ASCellNode alloc] initWithViewControllerBlock:^UIViewController * _Nonnull{
        return  [[AnimalTableController alloc] initWithAnimals:animals];
    } didLoadBlock:nil];
    
    return node;
}

我們來(lái)總結(jié)下這部分:

  • 1: 盡管這個(gè)版本中沒(méi)有進(jìn)行模塊化分,但是首先獲取數(shù)據(jù)模型是個(gè)好習(xí)慣宿崭。
  • 2: 這一次亲铡,你使用的正是強(qiáng)大的 -initWithViewControllerBlock: 構(gòu)造器。你所要做的就是返回一個(gè)block葡兑,這個(gè) block 返回你提前設(shè)置好的 tableNodeController奖蔓,它將自動(dòng)展示在pager 的 頁(yè)面中。真是太酷了??~

一旦你添加了這個(gè)方法讹堤,你將擁有一個(gè)完整功能的 Pagar吆鹤,其中的 cell 是從你原先創(chuàng)建的 tableNodeController 生成的。現(xiàn)在洲守,就可以在用戶的垂直和水平滑動(dòng)下檀头,充分發(fā)揮二維預(yù)加載的功能!

要查看這個(gè) AsyncDisplayKit 2.0 教程完整的項(xiàng)目岖沛,點(diǎn)擊這里進(jìn)行下載暑始。如果你想查看swift版本,這里也有婴削。

準(zhǔn)備好之后廊镜,請(qǐng)轉(zhuǎn)到該項(xiàng)目的第2部分,了解 AsyncDisplayKit 2.0 引入的強(qiáng)大的新的布局系統(tǒng)唉俗。

如果你想先進(jìn)行深入了解嗤朴,你可以閱讀 AsyncDisplayKit主頁(yè) 的文檔。Scott Goodson(AsyncDisplayKit的原創(chuàng)作者)也有幾個(gè)你可能會(huì)感興趣的話題虫溜。最近的話題很好的概述了一些框架對(duì)處理大圖片存在問(wèn)題的的嘗試雹姊。

你可能會(huì)對(duì) Paper的構(gòu)建感興趣。雖然當(dāng)時(shí)并沒(méi)有開(kāi)源衡楞,并且有許多地方發(fā)生了變化吱雏,但看到這一切的開(kāi)始還是挺有意思的。

這里有一個(gè) public Skack channel,歡迎來(lái)提問(wèn)~

著作權(quán)聲明

AsyncDisplayKit 2.0 Tutorial: Getting Started
轉(zhuǎn)載AsyncDisplayKit 2.0 教程:入門(mén)「譯」

相關(guān)資料:
iOS 開(kāi)發(fā)一定要嘗試的 Texture(ASDK)

TextTure文檔l

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末瘾境,一起剝皮案震驚了整個(gè)濱河市歧杏,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌迷守,老刑警劉巖犬绒,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異兑凿,居然都是意外死亡凯力,警方通過(guò)查閱死者的電腦和手機(jī)茵瘾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)咐鹤,“玉大人拗秘,你說(shuō)我怎么就攤上這事】对荩” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵晨雳,是天一觀的道長(zhǎng)行瑞。 經(jīng)常有香客問(wèn)我,道長(zhǎng)餐禁,這世上最難降的妖魔是什么血久? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮帮非,結(jié)果婚禮上氧吐,老公的妹妹穿的比我還像新娘。我一直安慰自己末盔,他們只是感情好筑舅,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著陨舱,像睡著了一般翠拣。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上游盲,一...
    開(kāi)封第一講書(shū)人閱讀 49,760評(píng)論 1 289
  • 那天误墓,我揣著相機(jī)與錄音,去河邊找鬼益缎。 笑死谜慌,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的莺奔。 我是一名探鬼主播欣范,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼令哟!你這毒婦竟也來(lái)了熙卡?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤励饵,失蹤者是張志新(化名)和其女友劉穎驳癌,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體役听,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡颓鲜,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年表窘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片甜滨。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡乐严,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出衣摩,到底是詐尸還是另有隱情昂验,我是刑警寧澤,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布艾扮,位于F島的核電站既琴,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏泡嘴。R本人自食惡果不足惜甫恩,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望酌予。 院中可真熱鬧磺箕,春花似錦、人聲如沸抛虫。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)建椰。三九已至击困,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間广凸,已是汗流浹背阅茶。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留谅海,地道東北人脸哀。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像扭吁,于是被迫代替她去往敵國(guó)和親撞蜂。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348

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

  • 這一系列的文章會(huì)從幾個(gè)方面對(duì) ASDK 在性能調(diào)優(yōu)方面策略的實(shí)現(xiàn)進(jìn)行分析侥袜,幫助讀者理解 ASDK 如何做到使復(fù)雜的...
    Draveness閱讀 7,619評(píng)論 8 110
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)蝌诡、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,059評(píng)論 4 62
  • 演講者Tim Urban,讀政府專業(yè)九杂,擁有寫(xiě)不完的論文颁湖,別人都是剛開(kāi)始就把第一時(shí)間寫(xiě)完宣蠕,而他總在最后一刻驚慌怪獸出...
    karmen123閱讀 314評(píng)論 0 0
  • 今午,又是修復(fù)實(shí)驗(yàn)甥捺,我依然沒(méi)能做出東西來(lái)抢蚀,準(zhǔn)確地說(shuō),我根本沒(méi)有什么思路镰禾,包括有什么要求皿曲,我要做些什么,只是按照稍有...
    cqmudhw閱讀 148評(píng)論 0 0