用 YogaKit 实现 Xib

前言

本文要讲述的是如何使用 YogaKit 提供的 FlexBox 布局能力来实现类似 Xib 的功能(Xib 布局是 AutoLayout)。

GitHub 地址:https://github.com/danleechina/YogaLayout

构想

Xib(StoryBoard) 的原理

先说一下 Xib(StoryBoard) 的原理:

  1. 在 Xcode 中使用 Interface Builder 来构建一个界面或者视图。这个过程其实就是创建、修改 XML 界面描述文件。右键 xib 类型的文件,在 Open As 中选择 Source Code,可以看到 xib 类型的文件其实就是苹果用自己定义的一套 XML 来描述视图
  2. 编译的时候,IDE 会解析项目中所有的 xib 类型的文件,根据苹果自己的一套规则(我们不可知),生成一个可归档的类,然后将该类归档生成一个 nib 类型的二机制文件。如果项目中有使用 xib 的话,解压打包出来的 ipa,就会看到这些 nib 类型的文件,这些文件就是 IDE 在编译时候解析生成的。
  3. 运行时,当需要展示一个 xib 描述的视图时,iOS 系统则会去加载 nib 文件得到之前编译时候生成的归档类实例,根据这个实例生成视图需要的所有子视图,并设置这些子视图的约束和属性
  4. 最后如果有设置 IBOutlet 的话,会将生成的视图赋值给其 owner。

想要了解 xib 更加深入的内容可以查看我之前翻译的一篇文章:macOS 和 iOS 中 Nib 文件实现原理以及最佳实践

可以看到,要实现类似 Xib 这样的工具需要如下一些条件:

  1. 一套类似的 XML 来描述视图的组成(比如某个视图有哪些子视图,它又是那个视图的子视图),配置视图的属性(比如配置 label 的 text 属性),以及定义视图之间的布局(比如使用 autolayout)
  2. 出于性能考虑,可以提前解析该 XML,生成类似 nib 的类
  3. 运行时解析该 XML(如果在编译阶段提前解析了,则不需要),将 XML 中视图的组成,视图的属性,视图的布局给提取出来,动态生成相应视图,并配置其属性、子视图、父视图、布局等
  4. 如果 XML 描述的文件有指定的 Outlet 的话,则将其赋值给相应的类

构想实现

定义 XML 描述视图规则


    
    

  1. 在这里,每一个 XML 标签名字是视图类的名字,以便运行时通过 NSClassFromString 得到类对象,再通过类对象生成该视图类的一个实例
  2. 每一个 XML 标签有一些属性,比如上面的 id 和 style。id 的作用等同于 IBOutlet,将动态生成的类实例赋值给其 owner,style 的作用是描述布局,然后将其设置到 YogaKit 中。还可以添加别的属性,比如说如果是 UILabel 的话设置 text="我是文本" 来描述其 text 属性,代码中使用 KVC 来实现
  3. style 属性的值指定多个的时候需要通过分号隔离,键值对通过冒号隔离
  4. 每一个 XML 标签会包含其他 XML 标签,比如上面 UIView 包含一个 UILabel 标签,一个自定义的 StarBarView 标签,意思就是说该 UIView 有两个子视图,第一个是一个 UILabel,第二个是自定义视图 StarBarView
  5. 为了简单,每一个类似该 XML 的文件只能有一个根标签

比如不能出现下列场景:




在这里,根标签有三个,第一个 UIView,第二个 UILabel,第三个 UIButton,这个情况目前不被允许(对 xib 了解的可能会知道从 nib 获取视图对象会返回一个数组,就是说 xib 可以有多个根层级的视图)

实现细节

  1. 如何解析 XML?为了简单起见我直接使用了苹果官方处理 XML 的类 NSXMLParser。实现代理方法,调用 parse 函数即可完成 XML 解析。有一点要注意,调用 parse 函数是同步的,也就是说当 parse 函数返回时,如果实现了代理方法,则代理方法均已经被使用过了。
  2. 解析 XML 的结果是一个树形的数据模型,该树形结构的每一个节点包含视图类的名字,视图的属性(包括视图的布局信息),子视图信息,以及父视图信息(没有父视图意味则是根节点)
  3. 从树形数据模型的根节点开始动态生成该视图的实例,并配置实例的属性,子视图信息和父视图信息等
  4. 在 XML 中有时候定义一个视图的宽高时会需要屏幕宽高的信息,并做一下简单表达式的计算,比如视图的高时屏幕的高的 2/3,这里做表达式计算的时候可以使用 NSExpression 来处理。
  5. 用 Swift 编写的视图类使用 Objective C 来动态生成的时候,需要加上当前二机制文件的名字,这个需要注意

未来

  1. 支持动态设置文本、颜色、图片、CGRect(结构体) 等属性
  2. 简化 Swift 中 Outlet 的设置
  3. 考虑能否去掉 Outlet,使用者传入数据,数据和视图能够双向绑定
  4. 支持 Debug 模式下不重新编译,仅需更改 XML 文件即可更新视图布局

参考

  1. XML 教程
  2. Flex 布局教程:语法篇
  3. Yoga Kit
  4. macOS 和 iOS 中 Nib 文件实现原理以及最佳实践

你可能感兴趣的:(用 YogaKit 实现 Xib)