工作生活

AutoLaytou相关记录

2019-07-03  本文已影响0人  7a946bf5d2ca

简要

通过Masonry设置约束后,无法再通过Frame对其调整位置。因为在真正布局显示到屏幕时,系统会根据约束从新计算Frame,设置过的Frame会失效,所以想要对利用Masonry约束过的view设置动画等,不能按照常规方式设置。


关于UIView的Layer,IOS提供了三个方法:

setNeedsLayout:
标记为需要重新布局,异步调用layoutIfNeeded刷新布局,不立即刷新,但layoutSubviews一定会被调用。
此方法会将view当前的layout设置为无效的,并在下一个upadte cycle里去触发layout更新。
此行为允许你将所有的布局更新合并到一个更新周期,这很适合用来优化性能。
setNeedDisplay在receiver标上一个需要被重新绘图的标记,
在下一个draw周期自动重绘,iphone device的刷新频率是60hz,也就是1/60秒后重绘。
layoutIfNeeded:
如果有需要刷新的,立即调用layoutSubviews进行布局(如果没有,不会调用layoutSubviews)。
使用此方法强制立即进行layout,从当前view开始,
此方法会遍历整个view层次(包括superviews)请求layout。
因此,调用此方法会强制整个view层次布局。
layoutIfNeeded不一定会调用layoutSubviews方法。
setNeedsLayout一定会调用layoutSubviews方法(有延迟,在下一轮runloop结束前)。
如果想在当前runloop中立即刷新,调用顺序应该是
[self setNeedsLayout];
[self layoutIfNeeded];
最好组合使用
layoutSubviews:
在layoutSubviews方法里对subviews重新布局。比如,我们想更新子视图的位置的时候,可以通过调用layoutSubviews方法,即可以实现对子视图重新布局。
layoutSubviews默认是不做任何事情的,用到的时候,需要在子类进行重写。
这个方法不能直接调用
1. init初始化不会触发layoutSubviews
2. addSubview会触发layoutSubviews钱,前提是frame有值
3. 设置view的Frame会触发layoutSubviews,前提是frame的值设置前后发生了变化
4. 滚动一个UIScrollView会触发layoutSubviews
5. 旋转Screen会触发父UIView上的layoutSubviews事件
6. 改变一个UIView大小的时候也会触发父UIView上的layoutSubviews事件
子类可以根据需要重写此方法,以执行更精确的子视图布局。
只有当子视图的自动调整、约束的行为不能满足你时,你才应该重写此方法

基于约束的AutoLayer的方法:

setNeedsUpdateConstraints:
控制 view 的约束是否需要更新。当一个自定义view的某个属性发生改变,并且可能影响到constraint时,
需要调用此方法去标记constraints需要在未来的某个点更新,系统然后会调用 updateConstraints,
以解决这个由属性改变带来的影响。
updateConstraintsIfNeeded:
立即触发约束更新,自动更新布局。
updateConstraints:
自定义view应该重写此方法在其中建立constraints. 
注意:要在实现在最后调用[super updateConstraints]
viewDidLayoutSubviews:
控制器的view布局子控件完成
awakeFromNib:
从xib或者storyboard加载完毕就会调用
initWithCoder:
只要对象是从文件解析来的,就会调用
awakeFromNib和initWithCoder同时存在会先调用initWithCoder:
awakeFromNib 相较于 initWithCoder 的优势是:当 awakeFromNib 执行的时候,
各种 IBOutlet 也都连接好了;而 initWithCoder 调用的时候,虽然子视图已经被添加到视图层级中,但是还没有引用。
如果你是基于 xib 或 storyboard 创建的控件,那么你可能需要对 IBOutlet 连接的子控件进行初始化工作,
这种情况下,你只能在 awakeFromNib 里进行处理。
只要跟xib&storyBoard有关 就会调这两个方法
drawRect:
drawRect是对receiver的重绘,能获得context; 
layoutSubviews方法调用先于drawRect;
一般用于绘图操作
如果在UIView初始化时没有设置rect大小,将直接导致drawRect不被自动调用。
1. 该方法在调用sizeThatFits后被调用,所以可以先调用sizeToFit计算出size。
2. 然后系统自动调用drawRect:方法。
3. 通过设置contentMode属性值为UIViewContentModeRedraw。那么将在每次设置或更改frame的时候自动调用drawRect:。
4. 直接调用setNeedsDisplay,或者setNeedsDisplayInRect:触发drawRect:,但是有个前提条件是rect不能为0. 

xib&storyboard、masonry设置动画

- (void)updateViewConstraints {
    //更新约束
    if (self.bAnimaiton) {
        self.viewLeft.constant = 100;
    }else{
        self.viewLeft.constant = 20;
    }
    [super updateViewConstraints];  
}
- (IBAction)btnClick:(id)sender {
    // 通知需要更新约束,但是不立即执行
    [self.view setNeedsUpdateConstraints];
    // 立即更新约束,以执行动态变换
    [self.view updateConstraintsIfNeeded];
    // 执行动画效果, 设置动画时间
    [UIView animateWithDuration:0.4 animations:^{
        [self.view layoutIfNeeded];
    }];
    self.bAnimaiton = !self.bAnimaiton;
}

实际使用中发小不调用setNeedsUpdateConstraints和updateConstraintsIfNeeded也可以,只不过需要在触发事件中就更新约束

- (IBAction)btnClick:(id)sender {
    self.bAnimaiton = !self.bAnimaiton;
    if (self.bAnimaiton) {
        self.viewLeft.constant = 100;
    }else{
        self.viewLeft.constant = 20;
    }

    [UIView animateWithDuration:0.4 animations:^{
//        [self.view setNeedsLayout]; 最好配套使用
        [self.view layoutIfNeeded];
    }];
}

也可以在layoutSubview里处理约束

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];
    if (self.bAnimaiton) {
        self.viewLeft.constant = 100;
    }else{
        self.viewLeft.constant = 20;
    }
}

- (IBAction)btnClick:(id)sender {
    [UIView animateWithDuration:0.4 animations:^{
        [self.view setNeedsLayout];//不调用此方法不会调用layoutSubviews
        [self.view layoutIfNeeded];
    }];
    self.bAnimaiton = !self.bAnimaiton;
}
以上三种办法都可以处理masonry&xib&stroyboard的动画,推荐第二种方式。

参考

Masonry
https://www.jianshu.com/p/d46bcc656e04
https://www.jianshu.com/p/a84f85729952
https://www.jianshu.com/p/1d1a1165bb04
https://juejin.im/post/5a30f24bf265da432e5c0070

上一篇下一篇

猜你喜欢

热点阅读