zoukankan      html  css  js  c++  java
  • UIScrollview 与 Autolayout 的那点事

    原文  http://www.cocoachina.com/ios/20151221/14757.html

    前言

    自从写了 介绍Masonry 那篇文章以后 就一直有人对UIScrollView的那个例子不是很理解 

    UIView *container = [UIView new];
    [scrollView addSubview:container];
    [container mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(scrollView);
        make.width.equalTo(scrollView);
    }];
    • 为什么要用一个container包含其他subview?

    • 为什么指定了edges 还要指定width? 不是多此一举吗?

    那么今天我就按照我的理解来说明一下这个问题

    梳理

    直入主题 要解释之前的问题 最重要的一个概念就是

    UIScrollView依靠与其subviews之间的约束来确定ContentSize的大小

    换成代码 是这个样子

    [scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(v1.mas_left);
        make.right.equalTo(v1.mas_right);
        make.top.equalTo(v1.mas_top);
        make.bottom.equalTo(v1.mas_bottom);
    }];

    这是因为UIScrollView是个非常特殊的view UIScrollView与其subview之间 相对位置的约束 并不会直接用于frame的计算 而是会转化为对ContentSize的计算 

    换句话说 当UIScrollView知道了 上下左右 的约束分别指向subview什么位置之后 只要subview的位置固定下来了 ContentSize的大小就确定下来了 

    下面来个简单的例子 强烈建议 配合demo来理解下面的例子(demo的链接在文尾) 

    请点击-> 在线演示 (为了方便理解 我将ContentSize用红线框了出来 另外为了查看ContentSize 我把UIScrollView的clipTobounds关闭了 可以通过左上角的开关来切换实际的效果)

    示例1

    [v1 mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(scrollView);
        make.width.equalTo(scrollView);
        make.height.equalTo(scrollView).multipliedBy(1.5);
    }];

    效果

    这里我建立了一个宽等于scrollview 高等于scrollview高度1.5倍的view 然后scrollview成功的计算出了ContentSize 

    关键就在于

    make.edges.equalTo(scrollView);

    这句话其实等同与之前我提到的

    [scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(v1.mas_left);
        make.right.equalTo(v1.mas_right);
        make.top.equalTo(v1.mas_top);
        make.bottom.equalTo(v1.mas_bottom);
    }];

    scrollview因为上面的约束 会以v1的大小来计算ContentSize

    示例2

    如果尝试改变v1的大小 会怎么样呢?

    [v1 mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(scrollView);
        
        make.size.equalTo(scrollView).sizeOffset(CGSizeMake(80, 80));
    }];

    效果

    能看到 当我仅改变v1的大小 而不变其他的东西的情况下 scrollview的ContentSize也是随着v1的大小变化而变化的 

    示例3

    接下来示例就会稍微复杂点 如果同时有两个view 会如何呢?

    [v1 mas_makeConstraints:^(MASConstraintMaker *make) {
        
        make.left.top.right.equalTo(scrollView).insets(UIEdgeInsetsMake(10, 10, 0, 10));
        
        make.width.equalTo(scrollView).multipliedBy(1.1);
        make.bottom.equalTo(v2.mas_top).offset(-50);
        make.height.equalTo(@200);
    }];
    [v2 mas_makeConstraints:^(MASConstraintMaker *make) {
        make.bottom.equalTo(scrollView);
        
        make.left.right.equalTo(v1).insets(UIEdgeInsetsMake(0, 50, 0, 50));
        make.height.equalTo(@250);
    }];

    效果

    这个例子中 scrollview的四个方向的约束并没有放在同一个subview上 而是分别指向了两个view 所以scrollview的ContentSize会根据两个view之间的约束来确定 

    示例4

    如果将四个方向的约束分别放到四个不同的view上面 会怎么样呢?

    CGSize size = CGSizeMake(200, 200);
    [v1 mas_makeConstraints:^(MASConstraintMaker *make) {
        make.centerY.equalTo(scrollView.mas_top);
        
        make.size.mas_equalTo(size);
    }];
    [v2 mas_makeConstraints:^(MASConstraintMaker *make) {
        make.centerX.equalTo(scrollView.mas_left);
        
        make.size.mas_equalTo(size);
        make.right.equalTo(v1.mas_left);
        make.top.equalTo(v1.mas_bottom);
    }];
    [v3 mas_makeConstraints:^(MASConstraintMaker *make) {
        make.centerX.equalTo(scrollView.mas_right);
        
        make.size.mas_equalTo(size);
        make.left.equalTo(v1.mas_right);
        make.top.equalTo(v1.mas_bottom);
    }];
    [v4 mas_makeConstraints:^(MASConstraintMaker *make) {
        make.centerY.equalTo(scrollView.mas_bottom);
        
        make.size.mas_equalTo(size);
        make.left.equalTo(v1.mas_left);
        make.top.equalTo(v2.mas_bottom);
    }];

    效果

    将四个方向的约束分别指向四个view的中心点 我们也能得到正确的ContentSize 

    如果你看懂了示例4的代码与效果 相信你对这个问题的所有疑惑都应该已经解除了

    那么再回到最开始那个问题

    make.edges.equalTo(scrollView);
    make.width.equalTo(scrollView);

    一般情况下我们使用UIScrollView来进行autolayout布局 都是为了实现类似Android中的线性布局(有很多杂的非重复性的subview 如果使用UITableView和UICollectionView太麻烦) 这时直接使用UIScrollView就会很灵活

    那么

    如果我们需要竖向的滑动 就把width设为和scrollview相同

    如果需要横向的滑动 就把height设为和scrollview相同

    就是这么简单

    小结

    源码和Demo请点 这里

    前不久@nixzhu也写了一篇关于 UIScrollView的文章 然后我在微博上回复说 “ 使用一个单一的containerView占满全部,然后把所有的subview添加到containerView中 ”不过nixzh 表示他是极力避免这样的 但是后在这个问题上 我是 极力推荐 这样使用的 

    就如同示例1和示例2一样 如果你需要添加subview 你只要简单的添加到v1上 并添加与v1的约束 就可以获得正确的ContentSize了

    如果不这样做 就类似示例3和示例4 这些边界约束都需要一个一个的设置 这其实是没有必要的

    使用单一的containerView其实是这个问题上的最佳实践

     
  • 相关阅读:
    Hive初步认识,理解Hive(一)
    Beeline里面执行hive脚本 函数nvl2()与replace()报错
    Navicat定时在MySQL与MySQL数据库之间自动传输数据
    Hive 报错 Error while compiling statement: FAILED: ParseException line 1:0 character '' not supported here (state=42000,code=40000)
    关于大数据T+1执行流程
    Hive部分函数解析
    关于JDK动态代理与Cglib代理
    关于Excel做表小知识记录
    Java实现自定义注解开发
    bzoj1179[Apio2009]Atm
  • 原文地址:https://www.cnblogs.com/hello-Huashan/p/5572558.html
Copyright © 2011-2022 走看看