欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

iOS自动布局(AutoLayout)之 NSLayoutAnchor

程序员文章站 2022-06-09 20:28:19
...

自动布局(AutoLayout)之 NSLayoutAnchor 方式使用

AutoLayout

自动布局(AutoLayout)是iOS6引入的关系布局,实现动态位置和多视图关系的布局方式,是对frame布局和AutoresizingMask的不足进行补充的一种方式,现在已经成为主流的布局方案,由于原始创建方式比较复杂,可以使用优秀的第三方框架方便创建约束(Swift: SnapKit, Objective-C: Masonary)。

自动布局创建约束方式:

  1. 基于frame属性自动转化AutoLayout的约束,需要translatesAutoresizingMaskIntoConstraints为true.
  2. 通过NSLayouConstraint创建,比较麻烦且代码量多。
  3. 通过VFL语法创建约束组添加,不适合复杂布局,且理解有一定难度。
  4. NSLayoutAnchor, iOS9.0后添加的布局特性,是原生代码布局中最方便的。
  5. 直接在xib或storyboard中添加,最方便简单的实现自动布局方式。

自动布局基本原则:

  1. 创建约束尽量参考依赖父视图。
  2. 约束意义明确完整,尽量避免约束冲突
  3. 代码添加约束,一定要将View的translatesAutoresizingMaskIntoConstraints属性设置为false,否则约束不起效果
  4. 先添加到父视图,再添加约束,否则会崩溃。

NSLayoutAnchor

NSLayoutAnchor是对AutoLayout创建约束的补充,核心还是NSLayoutConstraint,可以避免过长创建约束代码。NSLayoutAnchor可以理解为约束描边,通过视图之间的边关系和X、Y轴关系,以及定义自身宽高来创建约束。

锚(Anchor)关系

苹果公司为UIView添加如下属性Anchor来作为约束参考

四边关系

Anchor(锚边) 描述
leadingAnchor 前边锚(与trailingAnchor成对使用)
trailingAnchor 后边锚
leftAnchor 左边锚(与rightAnchor成对使用)
rightAchor 右边锚
topAnchor 上边锚
bottomAnchor 下边锚

大小关系

Anchor(锚) 描述
widthAnchor 宽度约束
heightAnchor 高度约束

中心点关系

Anchor(锚点) 描述
centerXAnchor X轴对齐关系
centerYAnchor Y轴对齐关系

基准线

Anchor(锚) 描述
firstBaseLineAnchor 文本首行基准线
lastBaeLineAnchor 文本最后一行基准线

基本使用

实现灰色View和橙色View对齐,且大小相同。

1.初始化视图,并添加到父视图

 private var grayView = UIView()
 private var orangeView = UIView()
 grayView.backgroundColor = .gray
 orangeView.backgroundColor = .orange
 // 1. 先添加到父视图
 view.addSubview(grayView)
 view.addSubview(orangeView)

2.设置取消自动转化frame为约束

// 2.设置取消自动转化frame为约束
 grayView.translatesAutoresizingMaskIntoConstraints = false
 orangeView.translatesAutoresizingMaskIntoConstraints = false

3.通过锚关系添加约束

				// 3. 添加约束
        grayView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 15).isActive = true
        grayView.topAnchor.constraint(equalTo: view.topAnchor, constant: 80).isActive = true
        grayView.heightAnchor.constraint(equalToConstant: 40).isActive = true
        grayView.widthAnchor.constraint(equalToConstant: 40).isActive = true
        grayView.rightAnchor.constraint(equalTo: orangeView.leftAnchor, constant: -15).isActive = true  // 注意这里的值为负值[是相对于orangeView坐标系来确定值]
        
        orangeView.centerYAnchor.constraint(equalTo: grayView.centerYAnchor).isActive = true
        orangeView.widthAnchor.constraint(equalToConstant: 40).isActive = true
        orangeView.heightAnchor.constraint(equalToConstant: 40).isActive = true

iOS自动布局(AutoLayout)之 NSLayoutAnchor
与创建NSLayoutConstraint一样,也可以设置约束优先级,大于等于,小于等于等关系。

关系值确定

不知道你对grayView.rightAnchor.constraint(equalTo: orangeView.leftAnchor, constant: -15).isActive = true这个约束有没有疑问?为啥 值是负的,如果是使用xib来添加约束,他们两个的关系应该是15。

那是因为这个约束值是以orangeView的left锚为原点坐标系来确定的,灰色right边在次坐标系中的数值就是负值。参考以下示例图

iOS自动布局(AutoLayout)之 NSLayoutAnchor

同理特别容易出错的还有需求,如果现在需要灰色view与橙色view的距离大于等于15.

90%的人会写如下错误代码:

grayView.rightAnchor.constraint(greaterThanOrEqualTo: orangeView.leftAnchor, constant: 15).isActive = true 
// 语义上描述就是: 灰色view的right边大于等于橙色left边15距离

事实真是这样吗?你看

iOS自动布局(AutoLayout)之 NSLayoutAnchor

他们反而重合了,那你说把值换为负值总可以了吧!

grayView.rightAnchor.constraint(greaterThanOrEqualTo: orangeView.leftAnchor, constant: -15).isActive = true 

然而并不是?你看下面这张图

iOS自动布局(AutoLayout)之 NSLayoutAnchor

由于是参考橙色left边的为原点的坐标系,所以是负值,又因为距离越大负得越多,值越小(-15 > -65)所以就需要使用小于等于,是不是和xib有点相反。

正确约束应该为:

grayView.rightAnchor.constraint(lessThanOrEqualTo: orangeView.leftAnchor, constant: -15).isActive = true 

Tips: 在创建leftAnchor或者TopAnchor,一般为正值和xib一致,但是rightAnchor和BottomAnchor就要注意参考哪个坐标系原点来取值,来决定正负值和大于等、小于等于关系选择

参考坐标系的确定是以参数中视图锚边为原点坐标系(注意:此坐标系,不同于view的坐标系,这是一个以边为原点的虚拟坐标系)

UILayoutGuide

UILayoutGuide用于辅助添加约束,它的作用就像一个透明的View,具备约束参考,但是不会渲染。

假如我们想让三个view水平对齐,且中间间距相等。我们就可以使用UILayoutGuide辅助实现。

  1. 创建view即layoutGuide

     		private var grayView = UIView()
        private var orangeView = UIView()
        private var redView = UIView()
        private var layouGuide1 = UILayoutGuide()
        private var layouGuide2 = UILayoutGuide()
    
  2. 添加view到父视图

    				// 1. 先添加到父视图
            view.addSubview(grayView)
            view.addSubview(orangeView)
            view.addSubview(redView)
    				// layoutGuide也需要添加进来
            view.addLayoutGuide(layouGuide1)
            view.addLayoutGuide(layouGuide2)
    
  3. 通过锚关系添加约束

    // 2.设置取消自动转化frame为约束
            grayView.translatesAutoresizingMaskIntoConstraints = false
            orangeView.translatesAutoresizingMaskIntoConstraints = false
            redView.translatesAutoresizingMaskIntoConstraints = false
            // 3. 添加约束
            
            // 添加layoutGuide的约束
            layouGuide1.widthAnchor.constraint(equalTo: layouGuide2.widthAnchor, multiplier: 1.0).isActive = true
            layouGuide1.heightAnchor.constraint(equalToConstant: 1).isActive = true
            layouGuide2.heightAnchor.constraint(equalToConstant: 1).isActive = true
            // 添加view和layouGuide的约束
            grayView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 30).isActive = true
            grayView.topAnchor.constraint(equalTo: view.topAnchor, constant: 80).isActive = true
            grayView.heightAnchor.constraint(equalToConstant: 40).isActive = true
            grayView.widthAnchor.constraint(equalToConstant: 40).isActive = true
            grayView.rightAnchor.constraint(equalTo: layouGuide1.leftAnchor).isActive = true
        
            layouGuide1.rightAnchor.constraint(equalTo: orangeView.leftAnchor).isActive = true
            orangeView.widthAnchor.constraint(equalToConstant: 40).isActive = true
            orangeView.heightAnchor.constraint(equalToConstant: 40).isActive = true
            orangeView.rightAnchor.constraint(equalTo: layouGuide2.leftAnchor).isActive = true
            
            layouGuide2.rightAnchor.constraint(equalTo: redView.leftAnchor).isActive = true
            redView.widthAnchor.constraint(equalToConstant: 40).isActive = true
            redView.heightAnchor.constraint(equalToConstant: 40).isActive = true
            redView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -15).isActive = true
            // 灰色、橙色、红色view和layoutGuide1、layoutGuide2水平中心对齐
             grayView.centerYAnchor.constraint(equalTo: layouGuide1.centerYAnchor).isActive = true
            orangeView.centerYAnchor.constraint(equalTo: grayView.centerYAnchor).isActive = true
             orangeView.centerYAnchor.constraint(equalTo: layouGuide2.centerYAnchor).isActive = true
             orangeView.centerYAnchor.constraint(equalTo: redView.centerYAnchor).isActive = true
    

代码量还是有点多,还是xib和storyboard香。

iOS自动布局(AutoLayout)之 NSLayoutAnchor

参考

  1. 官网文档
  2. 通过VFL语法实现AutoLayout约束添加
相关标签: # UI控件