限界までUXを向上させる! Facebook paperのようなアプリを最新UIライブラリAsyncDisplayKitでヌルヌルな操作感を実現しよう！

by mixiappwchr

![スクリーンショット 2014-12-05 0.43.55.png](https://qiita-image-store.s3.amazonaws.com/0/37731/9c92234d-a8d5-a3f0-e23a-b5ba6dbae854.png)


Facebook paperがでて、大分たちました。あのUIを実現するライブラリがfacebookから出ることを心待ちにしていた人も多いかと思います。アニメーション部分については既にfacebook pop が公開されていましたが、いよいよあのUXを支えるライブラリがfacebookから公開されました。


# AsyncDisplayKit

http://asyncdisplaykit.org/


基本的にはUIKitよりもUI操作を阻害することなくスムーズなインターフェースを提供するためのライブラリです。
なかなかサンプルだけをみても結構伝わりづらいライブラリですが、基本的にはUIKitではないUIライブラリ群になります。

存在するのは最低限のものだけですが、テキスト、イメージ、TableView,CollectionViewがそろっているので一通りのことはできそうです。


# クラス類

## ASImageNode
UIImageViewの代替です。

## ASNetworkImageNode
ネットワークからのimage loadできるバージョンです。

## ASMultiplexImageNode

こちらは複数のデータロードを行うことができるimageViewです。sampleだとworst,medium,bestといった風に品質を分けながらロードすることが可能なようです。
    

## ASCollectionView   
UICollectionViewの代替です。まだpodsには入ってませんがmasterにはあります。

## ASTableView
UITableViewの代替です。

## ASCellNode
ASCollectionViewやASTableViewでつかうUITableViewCellやUICollectionViewCellの代替です。
  
## ASTextCellNode
ASCellNodeをカスタムしたリファレンス実装です。

## ASTextNode
UITextViewの代替。裏でTextKitを用いています。


どうでしょう？最低限のものだけですね！

# 実装例
例えばASCollectionViewの実装ですが例として

```
- (ASCellNode *)collectionView:(ASCollectionView *)collectionView nodeForItemAtIndexPath:(NSIndexPath *)indexPath
{
    ASImageCellNode *node = [[ASImageCellNode alloc] initWithSize:CGSizeMake(120,180)];
    NSString *urlString = [self.itemProvider.getList objectAtIndex:indexPath.row];
    [node setURL: [NSURL URLWithString:urlString]];
    
    return node;
}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    return 10;
}
```
と言った風にCollectionViewと同じようなインターフェースを持っています。
ここで使用しているASImageCellNodeは独自で実装したCellViewの用なものになります

実装は以下の通り。

```
#import "ASImageCellNode.h"
#import <AsyncDisplayKit.h>
@interface ASImageCellNode ()
@property(nonatomic) ASNetworkImageNode *imageNode;
@property(nonatomic) CGSize nodeSize;
@end

@implementation ASImageCellNode

- (instancetype)initWithSize:(CGSize)size
{
    if (!(self = [super init]))
        return nil;
    _nodeSize = size;
    _imageNode = [[ASNetworkImageNode alloc] initWithCache:nil downloader:[[ASBasicImageDownloader alloc] init]];
    
    [self addSubnode:_imageNode];
    
    return self;
}

- (CGSize)calculateSizeThatFits:(CGSize)constrainedSize
{
    
    return _nodeSize;
}

- (void)layout
{
    _imageNode.frame = CGRectInset(self.bounds,0,0);
}

- (void)setURL:(NSURL *)url
{
    [self.imageNode setURL:url];
    
}

@end
```

- (CGSize)calculateSizeThatFits:(CGSize)constrainedSizeを実装することでサイズ計算を行います。

サンプルで作ったUIKitとの比較動画です。


![スクリーンショット 2014-12-05 1.19.34.png](https://qiita-image-store.s3.amazonaws.com/0/37731/d36546ad-c45d-9427-f0a3-ba762187fd85.png)

https://www.youtube.com/watch?v=0YBvj-gFDAg&feature=youtu.be

UIKitのままだとロードがまばらですが、AsyncDisplayKitだとスムーズに読み込んでますね！


# 所感

このライブラリは決して普段の開発を楽にしたり便利にしたりするようなライブラリではありません。
むしろ開発は通常のUIKitのAPIを素直に使えないので大変になります。

同梱のexampleをみてもメリットが伝わりづらいものばかりだったのと、

自前で実装してみたのですが、現状はAPIも少なく、UIスレッドを阻害しないというのは普段からやっていることなので、上記の例くらいだとそこまでメリットを感じませんでしたが、ASMultiplexImageNodeとかもちゃんと使うと画像を多用する最近のアプリだと結構使えそうです。

またAPIはこれからどんどん増えていきそうなので今後に期待です。

限界までUI,UXにこだわりたい！60fpsで動くアプリを作ろうという方はぜひ試してみてください！