iOS AutoLayout

2019-07-22  本文已影响0人  Coder_Cat

iOS AutoLayout

AutoLayout的使用

1.IB方式实现自动布局

2.VFL/NSLayoutConstrais方式实现自动布局

功能 表达式
垂直方向 V:
水平方向 H:
Views [view1],[View2]
SuperView ` `
关系(不写默认==) >=,==,<=
空间,间隙(不写默认值8) -
优先级 @value
        let topView = UIView()
        topView.backgroundColor = UIColor.red
        topView.translatesAutoresizingMaskIntoConstraints = false
        
        let middleView = UIView()
        middleView.backgroundColor = UIColor.green
        middleView.translatesAutoresizingMaskIntoConstraints = false
    
        
        let bottomView = UIView()
        bottomView.backgroundColor = UIColor.blue
        bottomView.translatesAutoresizingMaskIntoConstraints = false
        
        view.addSubview(topView)
        view.addSubview(middleView)
        view.addSubview(bottomView)
        /*
         oc 中 NSDictionaryOfVariableBindings(v1,v2,v3)相当于[NSDictionary dictionaryWithObjectsAndKeys:v1,@“v1”,v2,@“v2”,v3,@“v3”,nil]
         */
    
        //水平约束,当为==时==可以省略
        let topViewHorizontalContriants = NSLayoutConstraint.constraints(withVisualFormat: "H:|-0-[topView]-==0-|", options:[], metrics: nil, views: ["topView":topView])
        view.addConstraints(topViewHorizontalContriants)
        //垂直约束
        let topViewVContriants = NSLayoutConstraint.constraints(withVisualFormat: "V:|-64-[topView(==100@1000)]", options: [], metrics: nil, views: ["topView":topView])
        view.addConstraints(topViewVContriants)
        
        //middleView的顶部和topView的底部对齐
        let middleTopC = NSLayoutConstraint.init(item: middleView, attribute: NSLayoutConstraint.Attribute.top, relatedBy: NSLayoutConstraint.Relation.equal, toItem: topView, attribute: NSLayoutConstraint.Attribute.bottom, multiplier: 1.0, constant: 0)
        //middleView的左边和topView的左边对齐对齐
        view.addConstraint(middleTopC)
        let middleleftC = NSLayoutConstraint.init(item: middleView, attribute: NSLayoutConstraint.Attribute.left, relatedBy: NSLayoutConstraint.Relation.equal, toItem: topView, attribute: NSLayoutConstraint.Attribute.left, multiplier: 1.0, constant: 0)
         view.addConstraint(middleleftC)
        //middleView的宽等于topView的宽度
        let middleWidthC = NSLayoutConstraint.init(item: middleView, attribute: NSLayoutConstraint.Attribute.width, relatedBy: NSLayoutConstraint.Relation.equal, toItem: topView, attribute: NSLayoutConstraint.Attribute.width, multiplier: 1.0, constant: 0)
         view.addConstraint(middleWidthC)
        
        //middleView的高度等于topView的高度
        let middleHeigitC = NSLayoutConstraint.init(item: middleView, attribute: NSLayoutConstraint.Attribute.height, relatedBy: NSLayoutConstraint.Relation.equal, toItem: topView, attribute: NSLayoutConstraint.Attribute.height, multiplier: 1.0, constant: 0)
        view.addConstraint(middleHeigitC)
        //bottomView的垂直方向上的约束,不写间距默认是8
        let bottomVC = NSLayoutConstraint.constraints(withVisualFormat: "V:[middleView]-[bottomView]-0-|", options: [], metrics: nil, views: ["middleView":middleView,"bottomView":bottomView])
        view .addConstraints(bottomVC)
        //水平约束
        let bottomHC = NSLayoutConstraint.constraints(withVisualFormat: "H:|-0-[bottomView]-0-|", options: [], metrics: nil, views: ["bottomView":bottomView])
        view.addConstraints(bottomHC)
view添加子视图.png
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.font = UIFont.systemFont(ofSize: 15)
        label.numberOfLines = 0;
        label.backgroundColor = UIColor.cyan
        bottomView.addSubview(label)

        //水平约束
        let labelHC = NSLayoutConstraint.constraints(withVisualFormat: "H:|-10-[label]-10-|", options: [], metrics: nil, views: ["label":label])
        bottomView.addConstraints(labelHC)
        //垂直约束,顶部对齐,高度自适应
        let labelVC = NSLayoutConstraint.constraints(withVisualFormat: "V:|-10-[label]", options: [], metrics: nil, views: ["label":label])
        bottomView.addConstraints(labelVC)
        label.text = "lalalalalaz汽车消费网lalalalalaz汽车消费网lalalalalaz三生三世lalalalalaz汽车消费网lalalalalaz汽车消费网lalalalalaz三生三世vlalalalalaz汽车消费网lalalalalaz汽车消费网lalalalalaz三生三世lalalalalaz汽车消费网lalalalalaz汽车消费网lalalalalaz三生三lalalalaz汽车消费网lalalalalaz汽车消费网lalalalalaz三生三世lalalalalaz汽车消费网lalalalalaz汽车消费网lalalalalaz三生三世vlalalalalaz汽车消费网lalalalalaz汽车消费网lalalalalaz三生三世lalalalalaz汽车消费网lalalalalaz汽车消费网lalalalalaz三生三lalalalaz汽车消费网lalalalalaz汽车消费网lalalalalaz三生三世lalalalalaz汽车消费网lalalalalaz汽车消费网lalalalalaz三生三世vlalalalalaz汽车消费网lalalalalaz汽车消费网lalalalalaz三生三世lalalalalaz汽车消费网lalalalalaz汽车消费网lalalalalaz三生三lalalalaz汽车消费网lalalalalaz汽车消费网lalalalalaz三生三世lalalalalaz汽车消费网lalalalalaz汽车消费网lalalalalaz三生三世vlalalalalaz汽车消费网lalalalalaz汽车消费网lalalalalaz三生三世lalalalalaz汽车消费网lalalalalaz汽车消费网lalalalalaz三生三lalalalaz汽车消费网lalalalalaz汽车消费网lalalalalaz三生三世lalalalalaz汽车消费网lalalalalaz汽车消费网lalalalalaz三生三世vlalalalalaz汽车消费网lalalalalaz汽车消费网lalalalalaz三生三世lalalalalaz汽车消费网lalalalalaz汽车消费网lalalalalaz三生三lalalalaz汽车消费网lalalalalaz汽车消费网lalalalalaz三生三世lalalalalaz汽车消费网lalalalalaz汽车消费网lalalalalaz三生三世vlalalalalaz汽车消费网lalalalalaz汽车消费网lalalalalaz三生三世"
        

        print(bottomView.constraints)
//        label.frame.size = CGSize(width: 10, height: 10)
        UIView.animate(withDuration: 3) {
//            self.label.setNeedsUpdateConstraints()
            self.label.layoutIfNeeded()
        }
        
blueView添加label.png

extension ViewController {
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        let labelHC1 = NSLayoutConstraint.constraints(withVisualFormat: "H:|-60-[label]-60-|", options: [], metrics: nil, views: ["label":label])
        bottomView.removeConstraints(labelHC!)
        bottomView.addConstraints(labelHC1)

        UIView.animate(withDuration: 3) {
//            self.bottomView.setNeedsUpdateConstraints()
            self.bottomView.layoutIfNeeded()
//            self.bottomView.updateConstraints()
//            self.bottomView.updateConstraintsIfNeeded()
        }
    }
}
更新约束.gif

小结


/*
withVisualFormat : VFL语句
options : 字典类型的值;这里的值一般在系统定义的一个enum里面选取,默认传空的字典
metrics : 一般为nil ,参数类型为NSDictionary,从外部传入 //衡量标准
views :  就是上面所加入到NSDictionary中的绑定的View,要求字典形式为 ["view":view,"label":label]
*/
open class func constraints(withVisualFormat format: String, options opts: NSLayoutConstraint.FormatOptions = [], metrics: [String : Any]?, views: [String : Any]) -> [NSLayoutConstraint]

/*
item : 指定需要添加约束的视图
attr1 : 指定视图一需要约束的属性
relatedBy : 指定视图一和视图二添加约束的关系(lessThanOrEqual 小于等于,equal 等于,greaterThanOrEqual 大于等于)
toItem : 指定视图一依赖关系的视图二;可为nil
attr2 : 指定视图一所依赖的视图二的属性,若view2=nil,该属性设置 NSLayoutAttributeNotAnAttribute
multiplier : 系数,情况一:设置A视图的高度 = A视图高度 * multiplier + constant;此时才会起作用;情况二:设置A视图和其他视图的关系或 toItem=nil,multiplier设置不等于0即可,若等于0会crash;       
constant :常量,间距的值
*/

public convenience init(item view1: Any, attribute attr1: NSLayoutConstraint.Attribute, relatedBy relation: NSLayoutConstraint.Relation, toItem view2: Any?, attribute attr2: NSLayoutConstraint.Attribute, multiplier: CGFloat, constant c: CGFloat)

基于约束的AutoLayer更新约束的方法

1、setNeedsUpdateConstraints
当一个自定义view的某个属性发生改变,并且可能影响到constraint时,需要调用此方法去标记constraints需要在未来的某个点更新,系统然后调用updateConstraints.
2、needsUpdateConstraints
constraint-based layout system使用此返回值去决定是否需要调用updateConstraints作为正常布局过程的一部分。
3、updateConstraintsIfNeeded
立即触发约束更新,自动更新布局。
4、updateConstraints
自定义view应该重写此方法在其中建立constraints. 注意:要在实现在最后调用[super updateConstraints]
uto Layout Process 自动布局过程
与使用springs and struts(autoresizingMask)比较,Auto layout在view显示之前,多引入了两个步骤:updating constraints 和laying out views。每一个步骤都依赖于上一个。display依赖layout,而layout依赖updating constraints。 updating constraints->layout->display
第一步:updating constraints,被称为测量阶段,其从下向上(from subview to super view),为下一步layout准备信息。可以通过调用方法setNeedUpdateConstraints去触发此步。constraints的改变也会自动的触发此步。但是,当你自定义view的时候,如果一些改变可能会影响到布局的时候,通常需要自己去通知Auto layout,updateConstraintsIfNeeded。
自定义view的话,通常可以重写updateConstraints方法,在其中可以添加view需要的局部的contraints。
第二步:layout,其从上向下(from super view to subview),此步主要应用上一步的信息去设置view的center和bounds。可以通过调用setNeedsLayout去触发此步骤,此方法不会立即应用layout。如果想要系统立即的更新layout,可以调用layoutIfNeeded。另外,自定义view可以重写方法layoutSubViews来在layout的工程中得到更多的定制化效果。
第三步:display,此步时把view渲染到屏幕上,它与你是否使用Auto layout无关,其操作是从上向下(from super view to subview),通过调用setNeedsDisplay触发,
因为每一步都依赖前一步,因此一个display可能会触发layout,当有任何layout没有被处理的时候,同理,layout可能会触发updating constraints,当constraint system更新改变的时候。
需要注意的是,这三步不是单向的,constraint-based layout是一个迭代的过程,layout过程中,可能去改变constraints,有一次触发updating constraints,进行一轮layout过程。
注意:如果你每一次调用自定义layoutSubviews都会导致另一个布局传递,那么你将会陷入一个无限循环中。

相关参考

上一篇下一篇

猜你喜欢

热点阅读