zoukankan      html  css  js  c++  java
  • xib模块化设计

    Swift之xib模块化设计

    转发:http://00red.com/blog/2016/07/27/tips-swift-xib-modular-design/

    一、解决问题

    Xib/Storybarod可以方便、可视化的设置约束,在开发中也越来越重要。由于Xib不能组件化,使得封装、重用都变得不可行。本文将介绍一种解决方案,来实现Xib组件化。

    二、模型块原理

    在介绍原理之前,我们先弄清楚两个概念:

    从上图可以看出,分别选中File’s Owner及根视图View,都有Custom Class属性面板。其中Class属性,有什么作用,区别又是什么呢?

    2.1 View的Class属性

    View的Class属性用于指定选中的视图的实例化类。Xib实际上是一个XML文件,在加载时,解析逻辑会根据XML内容,创建并设置View实例。而此处的Class就是告诉解析逻辑,想要创建什么类的实例。如果此处设置为UIButton,则解析逻辑会生成一个UIButton的实例。

    2.2 File’s Owner的Class属性

    Feile’s Owner的Class属性,大部分情况下,都为UIViewController及其子类。

    1
    2

    public func loadNibNamed(name: String!, owner: AnyObject!, options: [NSObject : AnyObject]!) -> [AnyObject]!

    从上面xib的加载接口可以看出,加载Xib需要指定一个owner类的实例,解析逻辑并没有像2.1创建新实例,而是使用参数名为owner的已创建好的实例。

    如果没有创建,为什么还要指定File's Owner的Class属性?
    

    此处设置的Class属性值,主要作用是通过关键字@IBOutlet,声明有哪些属性及方法可以建立关联关系。解析逻辑会将关联视图的引用赋值给owner的对应属性,触发事件则执行owner.method()方法。目的为了在owner中,就可以方便的处理界面相关的业务逻辑。可以这样理解,File’s Owner的Class,是关联接口声明,loadNibNamed传入的owner是实现。

    Tips

    File’s Owner的Class属性,起一个声明作用,告知哪些属性及方法可以使用。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class ILViewController: UIViewController {

    @IBOutlet weak var label: UILabel!

    }


    class ILFlagController: UIViewController {

    @IBOutlet weak var label: UILabel!

    }

    既然如此(如上面代码),使用loadNibNamed方法加载Xib时,owner参数传入ILViewController实例,而Xib中File’s Owner的Class却设置为ILFlagController,是否可行?答案:可行。

    2.4 Xib模块化原理

    在Storybarod/Xib中,与组件化有关的只有视图的Class属性。视图是由xib解析逻辑创建,所以要实现组件化,就要在此Class实例化时,自动执行加载子xib模块的功能。

    三、工具类源码

    为了实现xib的模块化,需要有一个小的功能类:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    import UIKit

    @objc class ILXibView: UIView {

    @IBOutlet var contentView: UIView!


    override init(frame: CGRect) {
    super.init(frame: frame)
    self.loadView()
    }

    required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    }



    override func awakeFromNib() {
    super.awakeFromNib()
    self.loadView()

    }

    override func layoutSubviews() {
    super.layoutSubviews()
    self.contentView.frame = self.bounds
    }

    private func getXibName() -> String {
    let clzzName = NSStringFromClass(self.classForCoder)
    let nameArray = clzzName.componentsSeparatedByString(".")
    var xibName = nameArray[0]
    if nameArray.count == 2 {
    xibName = nameArray[1]
    }
    return xibName
    }


    func loadView() {
    if self.contentView != nil {
    return
    }
    self.contentView = self.loadViewWithNibName(self.getXibName(), owner: self)
    self.contentView.frame = self.bounds
    self.contentView.backgroundColor = UIColor.clearColor()
    self.addSubview(self.contentView)
    }

    private func loadViewWithNibName(fileName: String, owner: AnyObject) -> UIView {
    let nibs = NSBundle.mainBundle().loadNibNamed(fileName, owner: owner, options: nil)
    return nibs[0] as! UIView
    }



    }

    四、实战示例

    4.1 封装Xib组件

    新建ILDemoView.xibILDemoView.swift两个文件(文件名要相同),并将ILDemoView文件的File’s Owner的Class设置为ILDemoView

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class ILDemoView: ILXibView {

    @IBOutlet weak var label: UILabel!

    override func awakeFromNib() {
    //一定要调用super
    super.awakeFromNib()
    self.label.text = "你好,中国"
    }

    }

    在xib文件中添加UILabel,并关联到ILDemoView中

    4.2 使用Xib组件

    新建Xib/Storyboard文件,添加一个UIView控件,并将此控件的Class属性设置为ILDemoView

    Tips

    使用的时候,先设置目标UIView的Class属性为ILDemoView,再将此UIView控件拖拽建立关联关系,会发现此时代码中属性类型已自动设置为ILDemoViewILXibView简单却非常实用,我们项目中已经大量的使用它,对于Xib的模块化封装,绝对是一利器。

     

    以前使用xib时一直都有点疑问,xib中可以有多个视图控件,但是从xib中load出来的是一个数组,那么怎么确定哪个对象对应的是哪个控件呢?

    可以实践一下:

    PurpleView.xib

    purpleview_xib.png

    随便在xib文件中加了几个视图。

    接下来将其load出来看看:

    MainViewController.m

    1
    2
    3
    4
    5
    6
    7
    8
    9
    - (void)logViewsFromXIB {
        NSLog(@"%s begin", __func__);
        NSArray *views = [[NSBundle mainBundle] loadNibNamed:@"PurpleView" owner:nil options:nil];
        for (int i = 0; i < views.count; i++) {
            id obj = views[i];
            NSLog(@"%d : %@", i, [obj class]);
        }
        NSLog(@"%s end", __func__);
    }

    控制台输出如下:

    1
    2
    3
    4
    5
    6
    2015-01-09 15:03:06.629 JLN-1_xib[3139:121677] -[MainViewController logViewsFromXIB] begin
    2015-01-09 15:03:06.635 JLN-1_xib[3139:121677] 0 : UIView
    2015-01-09 15:03:06.635 JLN-1_xib[3139:121677] 1 : UIButton
    2015-01-09 15:03:06.636 JLN-1_xib[3139:121677] 2 : UITableView
    2015-01-09 15:03:06.636 JLN-1_xib[3139:121677] 3 : UILabel
    2015-01-09 15:03:06.636 JLN-1_xib[3139:121677] -[MainViewController logViewsFromXIB] end

    结论:

    从xib中load出来的views数组中视图对象的排列顺序和xib scene中的对象排列顺序一致(其实就是xml文件中元素的排序而已)。如下:

    purpleview_xib_scene.png

    可以将其打乱并重新运行程序查看结果。

    直接下载demo

    2016.8.2更新

    感谢 霰雪 检查出ILXibView在6S不居中对齐问题,文章已经更新,感谢大家的支持。

     
     
    版权声明:一叶原创,采用 署名-非商业性使用-相同方式共享 3.0 中国大陆 许可协议
  • 相关阅读:
    zabbix 4.0 监控磁盘IO的实施笔记
    梅登黑德定位系统
    sdrplay sdr 支持的sample rate
    记录一下几个中移动可以PING的检测地址及部份DNS设置
    升级mariadb 10后目录权限问题的笔记
    C#单独启动进程的几种方式及使用特点(使用不当导致端口无法释放)
    SqlBulkCopy批量插入数据时,不执行触发器和约束的解决方法
    C# 处理大量数据的技巧
    C# 几种集合性能比较
    WPF学习网址整理
  • 原文地址:https://www.cnblogs.com/nelsen-chen/p/6807475.html
Copyright © 2011-2022 走看看