奇怪的 AutoLayout / VFL 居中问题

iOSadow • 于 2015-10-31 08:23:43 +0800 • 最后由 x19112015-12-04 01:33:03 +0800 6105 阅读

奇怪的 AutoLayout / VFL 居中问题

如果我们有一个 UIView(frameView), 宽 300, 高 200, 要把他放在中间,如果使用 AutoLayout,那需要很多代码:

let frameView = UIView()
    frameView.translatesAutoresizingMaskIntoConstraints = false
    self.view.addSubview(frameView)
    frameView.backgroundColor = UIColor(white: 1.0, alpha: 0.3)
let frameView_constraints_centerX = NSLayoutConstraint(item: frameView, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.CenterX, multiplier: 1.0, constant: 0.0)
let frameView_constraints_centerY = NSLayoutConstraint(item: frameView, attribute: NSLayoutAttribute.CenterY, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.CenterY, multiplier: 1.0, constant: 0.0)
let frameView_constraints_width = NSLayoutConstraint(item: frameView, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1.0, constant: 300.0)
let frameView_constraints_height = NSLayoutConstraint(item: frameView, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1.0, constant: 200.0)
self.view.addConstraints([frameView_constraints_centerX,frameView_constraints_centerY,frameView_constraints_width, frameView_constraints_height])

我们能看到屏幕中间有一个 300 * 200 的 UIView。但是这样写实在太啰嗦了。

还好, 我们还可以用 VFL,虽然还是有点麻烦,不过要简化很多

let frameView = UIView()
    frameView.translatesAutoresizingMaskIntoConstraints = false
    self.view.addSubview(frameView)
    frameView.backgroundColor = UIColor(white: 1.0, alpha: 0.3)
    let layout_frameView = ["frameView":frameView]
let frameView_constraintsX = NSLayoutConstraint.constraintsWithVisualFormat("H:|-[frameView(300.0)]-|", options: NSLayoutFormatOptions.AlignAllCenterX, metrics: nil, views: layout_frameView)
let frameView_constraintsY = NSLayoutConstraint.constraintsWithVisualFormat("V:|-[frameView(200.0)]-|", options: NSLayoutFormatOptions.AlignAllCenterY, metrics: nil, views: layout_frameView)
self.view.addConstraints(frameView_constraintsX)
    self.view.addConstraints(frameView_constraintsY)

看上去这样的约束条件应该是很简单的,但是我们却看到的是一个错误的约束提示。

我在网上搜了一圈,后来改成了这样的就正确了:

let frameView = UIView()
    frameView.translatesAutoresizingMaskIntoConstraints = false
    self.view.addSubview(frameView)
    frameView.backgroundColor = UIColor(white: 1.0, alpha: 0.3)
    let layout_frameView = ["frameView":frameView,"superView":self.view]
let frameView_constraintsX = NSLayoutConstraint.constraintsWithVisualFormat("H:[frameView(300.)]-(<=1)-[superView]", options: NSLayoutFormatOptions.AlignAllCenterY, metrics: nil, views: layout_frameView)
    let frameView_constraintsY = NSLayoutConstraint.constraintsWithVisualFormat("V:[frameView(200.0)]-(<=1)-[superView]", options: NSLayoutFormatOptions.AlignAllCenterX, metrics: nil, views: layout_frameView)
    self.view.addConstraints(frameView_constraintsX)
    self.view.addConstraints(frameView_constraintsY)

来源:

虽然解决了问题,但是这个 VFL 写的实在是太奇怪了:

  • H:[frameView(300.)]-(<=1)-[superView] 中间必须指定 (<=1) (<=0) 也可以,但不明白为啥这么写;
  • 必须指定 superView 而不是 |, 这个说的还稍微可以接受;
  • 仔细看 options, H 中使用的是 AlignAllCenterY, V 中使用的是 AlignAllCenterX,我一开始自然而来的是 H 中使用 AlignAllCenterX, V 中使用 AlignAllCenterY, 看了好久才发现是反过来写的。

看了 StackOverflow.com 上面的讨论,也没看出原因来。

大家来看看到底是为什么呢?

回复: 7
  • dugege 2015-10-31 21:21:14 +0800

    甲骨文不熟

  • tgz 2015-11-01 19:55:45 +0800

    为何不用cartographysnapkit 这些用起来很方便的库。。。VFL直接看不懂。。。

  • adow 2015-11-01 19:59:39 +0800

    我在项目中用 caryography,虽然很无趣,有时也会研究下系统自带的方法,毕竟如果我想写个单独的组件的时候,我不想去依赖任何第三方的布局工具

  • adow 2015-11-01 20:00:19 +0800

    @tgz 我在项目中用 caryography,虽然很无趣,有时也会研究下系统自带的方法,毕竟如果我想写个单独的组件的时候,我不想去依赖任何第三方的布局工具

  • tgz 2015-11-01 20:07:59 +0800

    @adow 好吧,给你赞一个

  • iBcker 2015-11-02 06:11:46 +0800

    @tgz 我也觉得苹果那个火星文表述好不直观···

  • x1911 2015-12-04 01:33:03 +0800

    非常感谢楼主 :yum: ,关于 VFL 的中文资料实在太少了

    其实这个写法和 interfacebuilder 里一样,x居中和y居中都是和superview平行的,所以不能简单的用 |

    (<=1) 这个可以省略 [frameView(300)][superView]就能用了,一样是居中

    [frameView(300)][superView(50)] 这样写还可以设计出居中偏上30的效果

    居中偏下的效果未试验出来,希望有同好告知,谢谢啦

  • 请注意单词拼写,以及中英文排版,参考此页
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`, 更多语法请见这里 Markdown 语法
  • 支持表情,见 Emoji cheat sheet
  • @name 会链接到用户页面,并会通知他
  • 上传图片, 支持拖拽和剪切板黏贴上传, 格式限制 - jpg, png, gif
Ctrl+Enter