MacDev 板


LINE

这是「纯程式码 Auto Layout 与概要教学」系列第二篇。总共会有三篇: * 从 setFrame 到 Auto Layout constraint * Visual Format Language (VFL) * 何时需要 UIStackView? 本系列文范例,都整理成 Swift Playground 在这专案里 https://github.com/denkeni/Auto-Layout-Programmatically (由於批踢踢不方便贴程式码,会精简摘录 含完整程式码与後续文章更新,请到网页版 https://goo.gl/AWOCI2 ) # 前言 纯程式码建立 Auto Layout constraint 在 iOS 6 刚推出时只有两种方式 其一是前篇文所述的线性关系 其二即是 Visual Format Language (VFL) 到 iOS 9 之後才有第三种方式 NSLayoutAnchor 然而苹果推出 Auto Layout 至今 几乎所有官方文件都推广透过 Interface Builder 来设定 constraint 这使得长期以来官方文件仅短短一页的 VFL 成为被束之高阁的瑰宝 # Visual Format Language (VFL) VFL 可读性不错,尤其在相当复杂程度的排版更是如此, 因为 VFL 的根本基础,就只有一段即见即所得的字串: ``` NSLayoutConstraint.constraints(withVisualFormat: VFLString, options: NSLayoutFormatOptions, metrics: [String : Any], views: [String : Any]) ``` 直接用实例来解释这个 API 我们改用 Auto Layout VFL 重做前篇例子 subviewB 的排版方式 分别设定 top, bottom, left, right 如下: https://cdn-images-1.medium.com/max/800/1*PZarxIPo6anPxjm8VysOhw.png
```精简版 VisualFormat: "V:|-(150)-[subviewB]-(150)-|" // V: Vertical VisualFormat: "H:|-(100)-[subviewB]-(100)-|" // H: Horizontal ``` 首先可以发现,VFL 其实就是自动帮我们生成多个 constraints 所以改用 += 来加入 constraints array 以中括号描述 view 以小括号描述数值 座标轴同样是由上往下(V)、由左向右(H)的方向描述 直线 `|` 表示为 superview `V:|-(150)-[subviewB] `表示为 subviewB 与其 superview 的 top 相距 150pt `V:[subviewB]-(150)-|` 表示为 subviewB 与其 superview 的 bottom 相距 150pt 两者合并起来就是相当直观的 `V:|-(150)-[subviewB]-(150)-|` 多数人不使用 options 而采用预设的空值 [] metrics 是用来描述 VFL 字串中「数值常数」的对应字典 views 则是用来描述 VFL 字串中「view 变数」的对应字典 故前例也可以修改成这样: ```精简版 let metrics = ["v": 150, "h": 100] VisualFormat: "V:|-(v)-[subview]-(v)-|" VisualFormat: "H:|-(h)-[subview]-(h)-|" ``` 由此也会发现 只用 VFL 无法描述前篇例子 subviewA, subviewC 的排版方式 因为 VFL 无法描述 centerX, centerY 因此,在许多情况下 VFL 还是得合并使用 constraint 来正确描述 subview 我们改用 Auto Layout VFL + NSLayoutAnchor 重做前篇例子 subviewA, subviewC 的排版方式 分别设定 centerX, centerY 和 width, height 如下: ```精简版 subviewA.centerXAnchor.constraint(equalTo: view.centerXAnchor) subviewA.centerYAnchor.constraint(equalTo: view.centerYAnchor) VisualFormat: "H:[subviewA(200)]" // width VisualFormat: "V:[subviewA(100)]" // height ``` 基於 VFL,也可以很容易地描述较为复杂的排版了: https://cdn-images-1.medium.com/max/800/1*_7pEUtg78EELsPmSXpL2UQ.png
```精简版 let metrics = ["p": 15] // padding VisualFormat: "H:|-(p)-[subview1(100)]-(10)-[subview2(120)]-(10)-[subview3]-(p)-|" "V:|-(p)-[subview1]-(p)-|" "V:|-(p)-[subview2]-(p)-|" "V:|-(p)-[subview3]-(p)-|" ``` 当然,在描述更为复杂的二维排版时 由於一段 VFL 只能描述一维排版关系 经常需要组合多段 VFL 才能完整而正确地描述排版 # 番外篇:NSLayoutFormatOptions 这个选项可在描述 X 方向 VFL 时,提供 Y 方向排版的准则 反之亦然。 以下述为例: https://cdn-images-1.medium.com/max/800/1*pyc3FixPF8775DPTkQTnVQ.png
```精简版 VisualFormat: "H:|-(15)-[subview1(100)]-(10)-[subview2(120)]-(10)-[subview3]-(15)-|", options: .alignAllTop, metrics: nil, views: viewsDict) VisualFormat: "V:[subview1(300)]" VisualFormat: "V:[subview2(200)]" VisualFormat: "V:[subview3(150)]" ``` # VFL Coding Style 以下是我自己偏好的 VFL Coding Style 原则,并藉此解释 VFL 的相容语法: * view 间距常数值加上括号 * view 间距常数值为等式时,不加上 `==` ex. `[view1]-(15)-[view2]` 而非 `[view1]-15-[view2]` 或 `[view1]-(==15)-[view2]` 这也是考量了使用不等式时,必须加上括号才能运作 ex. `[view1]-(>=15)-[view2]` * view 间距常数值为 0 时,依然要标示出来 ex. `[view1]-(0)-[view2]` 而非 `[view1][view2]` ex. `|-(0)-[view]-(0)-|` 而非 `|[view]|` * 不使用预设的间距 ex. `[view1]-(8)-[view2]` 而非 `[view1]-[view2]`(两者效果相同) P.S. 有一专案 [Swiftstraints](https://github.com/Skyvive/Swiftstraints) 将 VFL 精简成仅需一段字串,字串内可直接取用变数, 便可省略了 metrics 与 views 参数。 -- 我最近写了一个叫作「工作咖啡馆」的 iOS App https://goo.gl/iBWJSs 我朋友拖拖拉拉也生出了 Android 版叫作「CaffeeTrip」 https://goo.gl/HnUQWQ --



※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 219.85.169.16
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/MacDev/M.1491279670.A.17A.html
1F:推 gogoqaz: 推 04/06 22:52
2F:推 seanbabby: 推 05/04 17:56
3F:推 Polestar: 推 05/13 00:09







like.gif 您可能会有兴趣的文章
icon.png[问题/行为] 猫晚上进房间会不会有憋尿问题
icon.pngRe: [闲聊] 选了错误的女孩成为魔法少女 XDDDDDDDDDD
icon.png[正妹] 瑞典 一张
icon.png[心得] EMS高领长版毛衣.墨小楼MC1002
icon.png[分享] 丹龙隔热纸GE55+33+22
icon.png[问题] 清洗洗衣机
icon.png[寻物] 窗台下的空间
icon.png[闲聊] 双极の女神1 木魔爵
icon.png[售车] 新竹 1997 march 1297cc 白色 四门
icon.png[讨论] 能从照片感受到摄影者心情吗
icon.png[狂贺] 贺贺贺贺 贺!岛村卯月!总选举NO.1
icon.png[难过] 羡慕白皮肤的女生
icon.png阅读文章
icon.png[黑特]
icon.png[问题] SBK S1安装於安全帽位置
icon.png[分享] 旧woo100绝版开箱!!
icon.pngRe: [无言] 关於小包卫生纸
icon.png[开箱] E5-2683V3 RX480Strix 快睿C1 简单测试
icon.png[心得] 苍の海贼龙 地狱 执行者16PT
icon.png[售车] 1999年Virage iO 1.8EXi
icon.png[心得] 挑战33 LV10 狮子座pt solo
icon.png[闲聊] 手把手教你不被桶之新手主购教学
icon.png[分享] Civic Type R 量产版官方照无预警流出
icon.png[售车] Golf 4 2.0 银色 自排
icon.png[出售] Graco提篮汽座(有底座)2000元诚可议
icon.png[问题] 请问补牙材质掉了还能再补吗?(台中半年内
icon.png[问题] 44th 单曲 生写竟然都给重复的啊啊!
icon.png[心得] 华南红卡/icash 核卡
icon.png[问题] 拔牙矫正这样正常吗
icon.png[赠送] 老莫高业 初业 102年版
icon.png[情报] 三大行动支付 本季掀战火
icon.png[宝宝] 博客来Amos水蜡笔5/1特价五折
icon.pngRe: [心得] 新鲜人一些面试分享
icon.png[心得] 苍の海贼龙 地狱 麒麟25PT
icon.pngRe: [闲聊] (君の名は。雷慎入) 君名二创漫画翻译
icon.pngRe: [闲聊] OGN中场影片:失踪人口局 (英文字幕)
icon.png[问题] 台湾大哥大4G讯号差
icon.png[出售] [全国]全新千寻侘草LED灯, 水草

请输入看板名称,例如:Soft_Job站内搜寻

TOP