美文网首页工作生活
AutoLaytou相关记录

AutoLaytou相关记录

作者: 7a946bf5d2ca | 来源:发表于2019-07-03 14:19 被阅读0次

    简要

    通过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

    相关文章

      网友评论

        本文标题:AutoLaytou相关记录

        本文链接:https://www.haomeiwen.com/subject/zeqthctx.html