分拆 View Controller 中的自动布局代码

当页面复杂起来的时候,或者说,当页面控件数量太多的时候,自动布局的代码也会逐渐繁琐起来,造成了 View Controller 中的代码繁重起来

因此,这里提供一种方法,将 UI 的布局代码移动到其他文件中,这个方法受到了 👉 这篇文章 的启发,大部分的代码也是从这里出来

布局的方法使用自动布局,而且还是用 SnapKit 的那种,语言使用的是 Swift 3

创建一个关于自动布局的协议

先创建一个文件,普通的 Swift 文件的那种,并在里面 import SnapKit

定义一个 protocol

protocol Layoutable {
    func layoutMaker() -> (ConstraintMaker) -> Void
    func layoutUpdater() -> (ConstraintMaker) -> Void
}

其中 layoutMaker() 使用来创建约束,layoutUpdater() 是用来更新约束


这里的 (ConstraintMaker) -> Void 是什么?

看下面一段代码,这是我们布局自定义控件的一般写法,至少是我吧

ivCalendar.snp.makeConstraints { (make) in
  make.left.equalTo(contentView).offset(PreviewCellConstants.marginToFrame)
  make.centerY.equalTo(lbDate)
  make.size.equalTo(PreviewCellConstants.LabelCalendar.size)
}

再看 makeConstraints 方法的定义

public func makeConstraints(_ closure: (_ make: ConstraintMaker) -> Void) {
   ConstraintMaker.makeConstraints(item: self.view, closure: closure)
}

可以看出,我们写的一大串的布局代码,其实是一个 Closure,类型是 (ConstraintMaker) -> Void,而这里,就是我们用来分拆代码的关键了


对于上面的 func layoutUpdater() -> (ConstraintMaker) -> Void 协议方法,很多时候,我们只需要 make,而不太需要 update,这里可以选择将它删除。但是,也可以为它实现一个默认的实现,也就是 protocol 的 extension

如果没用到 func layoutUpdater() -> (ConstraintMaker) -> Void 这个方法,而且不作处理(删除它,或者提供默认实现),那么,在 implement 协议的时候,编译器将就会报错:没有 conforms to protocol

Layoutabel 的默认实现,只是简单地返回一个空的 Closure,当我们有实现对应的方法时,调用的将会是后者

extension Layoutable {
    func layoutMaker() -> (ConstraintMaker) -> Void {
        return { make in
            
        }
    }
    
    func layoutUpdater() -> (ConstraintMaker) -> Void {
        return { make in
            
        }
    }
}

为 UIView 添加布局相关的方法

在与协议的同一个文件中,顺便向 UIView 添加一个 extension,添加布局方法,这个方法,是之后在 View Controller 中用到的一行代码实现布局的方法


// MARK: - 自动布局的 extension
extension UIView {
    func makeLayout(layouter: Layoutable) {
        snp.makeConstraints(layouter.layoutMaker())
    }
    
    func updateLayout(layouter: Layoutable) {
        snp.updateConstraints(layouter.layoutUpdater())
    }
}

可以看到,snp.makeConstraints(...) 这一句,正是我们布局时写得算是最多的一句代码了。但现在,我们将会很少看到它了

同时,我们也可以看到,snp.makeConstraints(...) 中传入的参数,都是通过协议来调用的(大致意思,意会一下吧),这也许就是 面向协议编程 的抽象吧

之后,我们的工作将会聚焦在:如何创建一个实现 Layoutable 协议的类和它的实例

为 UI 控件的布局代码创建一个文件

下面的工作,可能就显得略烦琐,甚至看起来有点“蠢”了

为 UI 控件创建一个文件

为你觉得需要的 UI 控件,创建一个普通的 Swift 文件,并 import SnapKit

创建一个 struct,并声明实现 Layoutable 协议

struct ClipRecordPanelLayout: Layoutable {
    
}

为什么使用 struct,而不是使用 class ?

我的理解是这样的:

对于 class,在赋值的时候,实例会对其属性(对象的那种)默认进行了一个强引用,而这种强引用,很多时候就是造成内存问题(像循环引用)的原因

而对于 struct,在赋值的时候,实例只会对属性进行一系列的复制,不带引用的复制,因此可以避免出现内存问题


定义一些属性

struct ClipRecordPanelLayout: Layoutable {
    var views: (UIView)
    var constants: (panelHeight: CGFloat?, bottomOffset: CGFloat?)
}

在布局的时候,我们通常需要其他的一些 view 来作为参照物,并且需要写死一些常量,因此,在这里,使用了 views 和 constants 来分别装载这些参照物和常量

views 和 constants 都是 tuple 的类型,使用 tuple 的原因是,tuple 可以(天生)存放不同类型的数据,并且,可以为其中的值进行命名

在这个例子中,constants 存放的都是 CGFloat? 类型,但也可以存放不同的类型,如

var constants: (bottomOffset: CGFloat, size: CGSize)

实现协议方法

struct ClipRecordPanelLayout: Layoutable {
    
    var views: (UIView)
    var constants: (panelHeight: CGFloat?, bottomOffset: CGFloat?)
    
    func layoutMaker() -> (ConstraintMaker) -> Void {
        let superView = views
        let (panelHeight, _) = constants
        return { make in
            make.bottom.equalTo(superView)
            make.left.right.equalTo(superView)
            make.height.equalTo(panelHeight!)
        }
    }
    
    func layoutUpdater() -> (ConstraintMaker) -> Void {
        let superView = views
        let (_, bottomOffset) = constants
        return { make in
            make.bottom.equalTo(superView).offset(bottomOffset!)
        }
    }
}

这里分别实现了 layoutMaker()layoutUpdater() 的方法,分别对应的是建立约束和更新约束的操作

在获取参照物和常量的时候,使用了 tuple 的解构,将数据分别存放到不同的变量中,不需要的数据,直接使用 _ 进行忽略

在 constants 中,其中的元素的数据类型使用的 CGFloat?,是因为这两个数据,并不是同时都需要用到,那么,为了方便起见,在需要某一个参数的时候,直接传 nil

所以,这里的一个文件,只定义了一类的约束(也许有多个 UI 控件的布局方式是一样的,就是常量不同罢了)

View Controller 中一句话完成控件的布局

定义完了一类控件的约束之后,最后,在 View Controller 中将约束应用到 UI 控件中,像这样:

panel.makeLayout(layouter: ClipRecordPanelLayout(with: (view), constants: (PanelHeight, nil)))

这样,就一句话实现了对 UI 控件的布局了,当然这是针对简单的情况,要是含有多个参照物和常量,还是需要将 Layoutable 的实例单独抽取出来新建,避免一行代码过长

References

MVVM与Controller瘦身实践

对了,还有这个。。。

到我托放在 GitHub 的地方阅读能进行开始跳转 😁

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,388评论 25 707
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,016评论 4 62
  • 在, 无涯的生涯里, 我们, 都曾幻想过那美丽的梦 美丽的梦和美丽的诗一样 可遇而不可求, 常常让我深陷其中, 不...
    奔跑的胖胖蜗牛阅读 267评论 2 3
  • 春节临近,很多人在朋友圈晒旅游的照片,那份傲娇的样子让人嫉妒,但机智的浪子哥又岂能会被表象所迷惑?讲真,要说风景,...
    萧看风云阅读 365评论 0 1
  • 对于刚进入职场的小白来说,EXCEL可谓是必备技能,熟练掌握并使用这种工具,会明显提高你的工作效率,减少加班时间。...
    艾斯微博阅读 2,554评论 13 106