ios开发整理iOS适配Texture

AsyncDisplayKit的使用

2018-08-14  本文已影响21人  风ai翔

AsyncDisplayKit的使用


一、简介

AsyncDisplayKit 是一个UI框架,最初诞生于 Facebook 的 Paper 应用程序。它是为了解决 Paper 团队面临的核心问题之一:尽可能缓解主线程的压力。它能在异步线程绘制修改UI,然后统一添加进内存渲染出来。

image

ASDK 的作者是 Scott Goodson (Linkedin),
他曾经在苹果工作,负责 iOS 的一些内置应用的开发,比如股票、计算器、地图、钟表、设置、Safari 等,当然他也参与了 UIKit framework 的开发。后来他加入 Facebook 后,负责 Paper 的开发,创建并开源了 AsyncDisplayKit。目前他在 Pinterest 和 Instagram 负责 iOS 开发和用户体验的提升等工作。

1.解决的问题

很多时候用户在操作app的时候,会感觉到不适那么流畅,有所卡顿。
ASDK主要就是解决的问题就是操作页面过程中的保持帧率在60fps(理想状态下)的问题。

造成卡顿的原因有很多,总结一句话基本上就是:
CPU或GPU消耗过大,导致在一次同步信号之间没有准备完成,没有内容提交,导致掉帧的问题。
具体的原理,在提升 iOS 界面的渲染性能文章中介绍的十分详细了,这里也不多阐述了。

2.优化原理

实际上,从上面的一些解释也可以看出,ASDK最大的特点就是"异步"。
将消耗时间的渲染、图片解码、布局以及其它 UI 操作等等全部移出主线程,这样主线程就可以对用户的操作及时做出反应,来达到流畅运行的目的。

ASDK 认为,阻塞主线程的任务,主要分为上面这三大类。

为了尽量优化性能,ASDK 尝试对 UIKit 组件进行封装:

3.Nodes节点

关系图
不需要响应触摸事件

4.安装

CocoaPods安装

pod 'AsyncDisplayKit'

Carthage安装

AsyncDisplayKit可以使用Carthage安装,将下面的代码添加进入Cartfile

github "facebook/AsyncDisplayKit"

在终端执行carthage update来构建AsyncDisplayKit库,会自动在项目根目录下生成Carthage名字的文件夹,里面有个build文件夹,可以用来framework到你打算使用的项目中

静态库

AsyncDisplayKit可以当做静态库引入

  • 拷贝整个工程到你的目录下,添加AsyncDisplayKit.xcodeproj到你的workspace
  • 在build phases中,在Target Dependencies下添加AsyncDisplayKit Library
  • 在build phases中,添加libAsyncDisplayKit.a, AssetsLibrary, Photos等框架到Link Binary With Libraries中
  • 在build settings中,添加-lc++和-ObjC到 project linker flags

二、使用

主要介绍常用控件ASTableNode/ASCollectionNode的使用,代码放在GitHub上的ASDK_Demo

1.ASImageNode

  • 使用ASNetworkImageNode的URL设置网络图片。
  • ASNetworkImageNode有图片下载的ASNetworkImageNodeDelegate
  • ASImageNode使用ASDK的图片管理类PINCache,PINRemoteImage
  • 如果不打算引入PINRemoteImage和PINCache,你会失去对jpeg的更好的支持,你需要自行引入你自己的cache系统,需要遵从ASImageCacheProtocol

2.ASTextNode

ASTextNode没有text属性,只能使用attributedText

//居中
NSMutableParagraphStyle * paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.alignment = NSTextAlignmentCenter;
        
labelNode.attributedText = [[NSAttributedString alloc] initWithString:@"居中文字" attributes:@{NSFontAttributeName: [UIFont systemFontOfSize:18],
                                                                                                      NSForegroundColorAttributeName:[UIColor blackColor],
                                                                                                      NSBackgroundColorAttributeName : [UIColor clearColor],
                                                                                                      NSParagraphStyleAttributeName:paragraphStyle}];

3.ASTableNode/ASCollectionNode

三、布局

引用1
引用2

ASDK 拥有自己的一套成熟布局方案,虽然学习成本略高,但至少比原生的 AutoLayout 写起来舒服,重点是性能比起 AutoLayout 好的不是一点点。(ASDK不支持autoLayout)

//下面这个方法就是用来建立布局规则对象,产生 node 大小以及所有子 node 大小的地方,你创建的布局规则对象一直持续到这个方法返回的时间点,经过了这个时间点后,它就不可变了。尤其重要要记住的一点事,千万不要缓存布局规则对象,当你以后需要他的时候,请重新创建。
//调用时机:ASDisplayNode 在初始化之后会检查是否有子视图,如果有就会调用
- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize 

1. 布局类

2.示例

ASAbsoluteLayoutSpec

- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize{
  self.childNode.style.layoutPosition = CGPointMake(100, 100);
  self.childNode.style.preferredLayoutSize = ASLayoutSizeMake(ASDimensionMake(100), ASDimensionMake(100));

  ASAbsoluteLayoutSpec *absoluteLayout = [ASAbsoluteLayoutSpec absoluteLayoutSpecWithChildren:@[self.childNode]];
  return absoluteLayout;
}

使用方法和原生的绝对布局类似

ASBackgroundLayoutSpec

- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize{
  ASBackgroundLayoutSpec *backgroundLayout = [ASBackgroundLayoutSpec backgroundLayoutSpecWithChild:self.childNodeB background:self.childNodeA];
  return backgroundLayout;
}

把childNodeA 做为 childNodeB 的背景,也就是 childNodeB 在上层,要注意的是 ASBackgroundLayoutSpec 事实上根本不会改变视图的层级关系

ASInsetLayoutSpec

- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize{
    ASInsetLayoutSpec *inset = [ASInsetLayoutSpec insetLayoutSpecWithInsets:UIEdgeInsetsZero child:_childNode];
    return insetLayout;
}

_childNode 相对于父视图边距都为 0,相当于填充整个父视图。

ASOverlayLayoutSpec

- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize{

  _photoNode.style.preferredSize = CGSizeMake(USER_IMAGE_HEIGHT*2, USER_IMAGE_HEIGHT*2);

  // INIFINITY(插入无边界)
  UIEdgeInsets insets = UIEdgeInsetsMake(INFINITY, 12, 12, 12);
  ASInsetLayoutSpec *textInsetSpec = [ASInsetLayoutSpec insetLayoutSpecWithInsets:insets child:_titleNode];

  return [ASOverlayLayoutSpec overlayLayoutSpecWithChild:_photoNode 
                                                 overlay:textInsetSpec];

}

类似于ASBackgroundLayoutSpec,都是设置层级关系

ASRatioLayoutSpec

- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize{
    ASRatioLayoutSpec *ratioLayout = [ASRatioLayoutSpec ratioLayoutSpecWithRatio:1.0f child:self.childNodeA];
    return ratioLayout;
}

比较常用的一个类,作用是设置自身的高宽比,例如设置正方形的视图

ASRelativeLayoutSpec

image
//把 childNodeA 显示在右上角。
    self.childNodeA.style.preferredSize = CGSizeMake(100, 100);
    ASRelativeLayoutSpec *relativeLayout = [ASRelativeLayoutSpec relativePositionLayoutSpecWithHorizontalPosition:ASRelativeLayoutSpecPositionEnd verticalPosition:ASRelativeLayoutSpecPositionStart sizingOption:ASRelativeLayoutSpecSizingOptionDefault child:self.childNodeA];
    return relativeLayout;
}

它可以把视图布局在:左上、左下、右上、右下四个顶点以外,还可以设置成居中布局。

ASCenterLayoutSpec

- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize{
    self.childNodeA.style.preferredSize = CGSizeMake(100, 100);
    ASCenterLayoutSpec *relativeLayout = [ASCenterLayoutSpec centerLayoutSpecWithCenteringOptions:ASCenterLayoutSpecCenteringXY sizingOptions:ASCenterLayoutSpecSizingOptionDefault child:self.childNodeA];
    return relativeLayout;
}

ASWrapperLayoutSpec

- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize{    
    ASWrapperLayoutSpec *wrapperLayout = [ASWrapperLayoutSpec wrapperWithLayoutElement:self.childNodeA];
    return wrapperLayout;
}

填充整个视图

ASStackLayoutSpec

可以说这是最常用的类,而且相对于其他类来说在功能上是最接近于 AutoLayout 的。
之所以称之为盒子布局是因为它和 CSS 中 Flexbox 很相似,不清楚 Flexbox 的可以看下这篇博客(HTML布局)

示例

- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize{

  // 当用户名和位置信息文本太长时,收缩堆放视图来适应屏幕,而不是将所有内容向右堆放
  ASStackLayoutSpec *nameLocationStack = [ASStackLayoutSpec verticalStackLayoutSpec];
  nameLocationStack.style.flexShrink = 1.0;
  nameLocationStack.style.flexGrow = 1.0;

  //如果从服务器获取位置信息,并检查位置信息是否可用
  if (_postLocationNode.attributedText) {
    nameLocationStack.children = @[_usernameNode, _postLocationNode];
  } else {
    nameLocationStack.children = @[_usernameNode];
  }

  //水平堆放
  ASStackLayoutSpec *headerStackSpec = [ASStackLayoutSpec   stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal
                     spacing:40     
              justifyContent:ASStackLayoutJustifyContentStart
                  alignItems:ASStackLayoutAlignItemsCenter
                    children:@[nameLocationStack, _postTimeNode]];

  //插入堆放
  return [ASInsetLayoutSpec insetLayoutSpecWithInsets:UIEdgeInsetsMake(0, 10, 0, 10)    
                                                child:headerStackSpec];

}

简单的说明下各个参数的作用:
1.direction:主轴的方向,有两个可选值:

  • 纵向:ASStackLayoutDirectionVertical(默认)
  • 横向:ASStackLayoutDirectionHorizontal
    2.spacing: 主轴上视图排列的间距,比如有四个视图,那么它们之间的存在三个间距值都应该是spacing
    3.justifyContent: 主轴上的排列方式,有五个可选值:
  • ASStackLayoutJustifyContentStart 从前往后排列
  • ASStackLayoutJustifyContentCenter 居中排列
  • ASStackLayoutJustifyContentEnd 从后往前排列
  • ASStackLayoutJustifyContentSpaceBetween 间隔排列,两端无间隔
  • ASStackLayoutJustifyContentSpaceAround 间隔排列,两端有间隔
    4.alignItems: 交叉轴上的排列方式,有五个可选值:
  • ASStackLayoutAlignItemsStart 从前往后排列
  • ASStackLayoutAlignItemsEnd 从后往前排列
  • ASStackLayoutAlignItemsCenter 居中排列
  • ASStackLayoutAlignItemsStretch 拉伸排列
  • ASStackLayoutAlignItemsBaselineFirst 以第一个文字元素基线排列(主轴是横向才可用)
  • ASStackLayoutAlignItemsBaselineLast 以最后一个文字元素基线排列(主轴是横向才可用)
    5.children: 包含的视图。数组内元素顺序同样代表着布局时排列的顺序

四、优缺点

  • 不支持大家常用的storyboard、xib、autoLayout,影响开发效率
  • 代码没有UIKit使用熟练
  • 网上资源少
  • 但是可以和UIKit混合开发
上一篇下一篇

猜你喜欢

热点阅读