iOS自动布局(AutoLayout)之 NSLayoutAnchor

自动布局(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(锚点)描述
centerXAnchorX轴对齐关系
centerYAnchorY轴对齐关系

基准线

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

Alt
与创建NSLayoutConstraint一样,也可以设置约束优先级,大于等于,小于等于等关系。

关系值确定

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

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

在这里插入图片描述

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

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

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

事实真是这样吗?你看

在这里插入图片描述

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

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

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

在这里插入图片描述

由于是参考橙色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香。

等宽layougGuide

参考

  1. 官网文档
  2. 通过VFL语法实现AutoLayout约束添加
  3. AutoLayou约束布局的发展
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值