AsyncDisplayKit 系列教程 —— 集成、示例

96
PonyCui
0.6 2015.11.24 10:57* 字数 786

集成

集成 AsyncDisplayKit 非常简单,使用 CocoaPods 添加 pod "AsyncDisplayKit" 然后 pod update 就可以了。什么?你还不愿意使用 CocoaPods?那你手动集成好了。

AsyncDisplayKit 只支持 iOS7.0 版本以上的系统,如果你使用的是 Swift,那么还需要将头文件引用 #import <AsyncDisplayKit/AsyncDisplayKit.h> 添加到 Swift-Bridging.h 中。

以下教程均使用 Swift 演示代码,Objective-C 使用方法也是类似的。

Hello, World!

一个 Demo 就应该从 ** Hello, World! ** 开始。

在 ViewController.swift 中添加以下代码

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        let textLabel = ASTextNode()
        textLabel.attributedString = NSAttributedString(string: "Hello, World!",
            attributes: [
                NSForegroundColorAttributeName: UIColor.blackColor(),
                NSFontAttributeName: UIFont.systemFontOfSize(17)
            ])
        textLabel.frame = CGRect(x: 50, y: 50, width: 100, height: 20)
        self.view.addSubnode(textLabel)
    }

}

我们做了些什么?

  1. 创建了一个ASTextNode的实例,名为textLabel;
  2. 为textLabel添加了一串富文本文字,并设定一些富文本属性,这里要注意,AsyncDisplayKit只支持富文本文字;
  3. 粗略地为textLabel设定一个frame;
  4. 把textLabel添加到view中。

整个过程其实和 UIView 的初始化并且 addSubview 没有太大的区别。 现在,你可以把 Demo Run 起来看看效果了。

控件对应关系

在 AsyncDisplayKit 的世界里,常用的 UIKit 控件都有对应的 AS 控件,以下是一个对照表。

UIKit AsyncDisplayKit
UIView ASDisplayNode
UILabel ASTextNode
UIImageView ASImageNode
UIButton ASButtonNode
UITableView ASTableView
UICollectionView ASCollectionView
UITableViewCell ASCellNode
UICollectionViewCell ASCellNode

ASDisplayNode 是所有控件的基类,它是整个 AsyncDisplayKit 界面库的核心,ASDisplayNode 不仅可以承载 AsyncDisplayKit 预定义的控件(例如 ASTextNode),也可以承载 UIKit 控件(例如 UISlider)。

使用Block方法返回 UIView 就可以承载 UIKit 控件

let slider = ASDisplayNode { () -> UIView! in
    return UISlider()
}

Measure ASTextNode

还记得刚刚我们只是粗略地设置了一下 textLabel.frame 吗?我们当然是希望textLabel中的文字有多大,它的frame就有多大。

在AsyncDisplayKit的世界中,我们不需要使用 NSAttributedString.boundingRectWithSize去计算ASTextNode的宽高。

我们使用以下方法去计算文本的宽高。

textLabel.measure(CGSize(width: view.bounds.width, height: CGFloat.max))
textLabel.frame = CGRect(x: 0, y: 50, width: textLabel.calculatedSize.width, height: textLabel.calculatedSize.height)

给定measure方法一个CGSize的参数,该参数定义了textLabel的最大宽度和最大高度,使用textLabel.calculatedSize获取计算好的宽高。

你会在后续的教程中知道,measure的强大之处。

ASImageNode

ASImageNode 是 UIImageView 的极佳替代品,ASImageNode 会在后台线程渲染好 UIImage ,然后再在主线程中呈现图像。 因此,ASImageNode可以极大地提升FPS数值。

如果是本地图像,你可以直接将一个 UIImage 实例赋值到 ASImageNode.image 中。

如果是网络图像,你应该使用 ASNetworkImageNode, 同时你需要为 ASNetworkImageNode 指定一个 ImageManager 用于管理网络请求、图像缓存等操作,一般搭配 SDWebImage 使用,你可以将以下的代码直接拷贝使用。

class ImageManager: NSObject, ASImageDownloaderProtocol, ASImageCacheProtocol {
    
    static let sharedManager = ImageManager()
    
    func fetchCachedImageWithURL(URL: NSURL!, callbackQueue: dispatch_queue_t!, completion: ((CGImage!) -> Void)!) {
        SDWebImageManager.sharedManager().cachedImageExistsForURL(URL) { (existed) -> Void in
            if existed {
                SDWebImageManager.sharedManager().downloadImageWithURL(URL, options: [], progress: nil, completed: { (cachedImage, _, _, _, _) -> Void in
                    dispatch_async(callbackQueue, { () -> Void in
                        if let image = cachedImage {
                            if let cImage = image.CGImage {
                                dispatch_async(callbackQueue, { () -> Void in
                                    completion(cImage)
                                })
                                return
                            }
                        }
                        completion(nil)
                    })
                })
            }
            else {
                dispatch_async(callbackQueue, { () -> Void in
                    completion(nil)
                })
            }
        }
    }
    
    func downloadImageWithURL(URL: NSURL!, callbackQueue: dispatch_queue_t!, downloadProgressBlock: ((CGFloat) -> Void)!, completion: ((CGImage!, NSError!) -> Void)!) -> AnyObject! {
        print(URL)
        let operation = SDWebImageDownloader.sharedDownloader().downloadImageWithURL(URL, options: [], progress: nil) { (image, data, error, _) -> Void in
            if let image = image {
                if let cImage = image.CGImage {
                    dispatch_async(callbackQueue, { () -> Void in
                        completion(cImage, error)
                    })
                    return
                }
            }
            completion(nil, error)
        }
        return operation
    }
    
    func cancelImageDownloadForIdentifier(downloadIdentifier: AnyObject!) {
        if let downloadIdentifier = downloadIdentifier as? SDWebImageOperation {
            downloadIdentifier.cancel()
        }
    }
    
}

添加一个 imageView 到 View 中。

let imageView = ASNetworkImageNode(cache: ImageManager.sharedManager,
    downloader: ImageManager.sharedManager)
imageView.frame = CGRect(x: 0, y: 100, width: view.bounds.size.width, height: 300)
imageView.contentMode = .ScaleAspectFill
imageView.clipsToBounds = true
imageView.URL = NSURL(string: "http://ww3.sinaimg.cn/large/7191b2ebgw1eyb1uontv4j21w02iou0r.jpg")!
self.view.addSubnode(imageView)

ASControlNode

ASImageNode、ASButtonNode、ASTextNode 同为 ASControlNode 子类,可以直接使用 .addTarget(self, action: "handleXXX", forControlEvents: .TouchUpInside) 为它们添加点击响应事件,而避免使用addGesture等方法。

结语

关于其它控件的使用方法,需要你自己去学习使用,此遍教程的Demo代码,你可以到这里下载 https://github.com/PonyCui/AsyncDisplayKit-Issue-2

下一篇教程,将指导你完成一个 ASTableView 的编写。

Pony's Open Source