美文网首页
iOS实战之从左往右自动填充布局页面

iOS实战之从左往右自动填充布局页面

作者: SuAdrenine | 来源:发表于2017-04-25 09:51 被阅读179次

    这里主要讲的就是控件宽度可变时的计算:

    方法一:
    这里使用一个宽度可变的Button,宽度不变的两个Label从左往右依次排布来测试。这里使用三组组合,每一组都用一个UIView包裹。

    首先为了测试,Button的标题,依次为:

    NSArray *btnTitle = @[@"我是一个长标题,很长很长很长很长的标题",@"我是短标题",@"标题"];
    

    titleLB的文本:
    titleLB.text = @"我是固定的标题";
    flagLB的文本:
    flagLB.text = @"立个flag";

    接下来就是计算:
    首先flagLB和titleLB的Size我们可以确定,可以给一个固定的值,也可以自动计算,由于button的title是可变的,所以我们采用自动计算

    这里计算,我们需要使用一个系统方法:

    CGSize constrainedSize = CGSizeMake(0, MAXFLOAT);
    CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;
    CGRect textRect = [title boundingRectWithSize:constrainedSize options:NSStringDrawingUsesLineFragmentOrigin 
      attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:15]} context:nil];
    

    这样就能计算一个文本的size,类似于iOS7以前使用的sizeWithFont,从这个Size可以获取文本的宽高。

    由于这三者的Size都确定了,布局写起来也就简单了:

    CGSize constrainedSize = CGSizeMake(0, MAXFLOAT);
    CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;
    CGRect textRect = [title boundingRectWithSize:constrainedSize options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:15]} context:nil];
            
    CGRect textRect2 = [titleLB.text boundingRectWithSize:constrainedSize options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:titleLB.font} context:nil];
            
    [button mas_remakeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(bgView.mas_left).offset(5);
        make.centerY.equalTo(bgView);
        make.height.mas_equalTo(20);
        make.width.mas_equalTo(MIN(textRect.size.width+10 , screenWidth-75-textRect2.size.width));
    }];
            
    [titleLB mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(button.mas_right).offset(5);
        make.height.mas_equalTo(18);
        make.width.mas_equalTo(textRect2.size.width);
        make.centerY.mas_equalTo(bgView);
    }];
            
    [flagLB mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(titleLB.mas_right).offset(5);
        make.size.mas_equalTo(CGSizeMake(60, 13));
        make.centerY.mas_equalTo(bgView);
    }];
    

    最关键的就是这句:
    make.width.mas_equalTo(MIN(textRect.size.width+10 , screenWidth-75-textRect2.size.width));
    可能有人会有疑问,这里不是能获得button的titleSize吗,直接设置titleSize.width不就可以了吗,如果这里title非常长的话,那么后面那两个label就会顶出到屏幕外面,这个是不符合设计的,所以需要对button的宽度进行限制。这里是对width进行判定,将titleSize和剩余屏幕宽度进行比较,如果button长度小于屏幕剩余宽度,则宽度为button的title宽度,如果button标题长度过长,则button的宽度为剩余屏幕宽度。
    最后上传一个效果:

    效果图

    方法二:
    理论

    • 约束优先级: 在Autolayout中每个约束都有一个优先级, 优先级的范围是1 ~ 1000。创建一个约束,默认的优先级是最高的1000。
    • Content Hugging Priority: 该优先级表示一个控件抗被拉伸的优先级。优先级越高,越不容易被拉伸,默认是250。
    • Content Compression Resistance Priority: 该优先级和上面那个优先级相对应,表示一个控件抗压缩的优先级。优先级越高,越不容易被压缩,默认是750

    所以默认情况下两边的label的Content Hugging和Content Compression优先级都是一样的,为了让右边的label完全显示,那么我们需要增大右边label的抗压缩级,或者减小左边label的抗压缩级,总之是得让右边的抗压缩级大于左边的label,这样才能让右边的label内容优先显示。

    UIView中关于Content Hugging 和 Content Compression Resistance的方法有:

    - (UILayoutPriority)contentHuggingPriorityForAxis:(UILayoutConstraintAxis)axis NS_AVAILABLE_IOS(6_0);
    - (void)setContentHuggingPriority:(UILayoutPriority)priority forAxis:(UILayoutConstraintAxis)axis NS_AVAILABLE_IOS(6_0);
    
    - (UILayoutPriority)contentCompressionResistancePriorityForAxis:(UILayoutConstraintAxis)axis NS_AVAILABLE_IOS(6_0);
    - (void)setContentCompressionResistancePriority:(UILayoutPriority)priority forAxis:(UILayoutConstraintAxis)axis NS_AVAILABLE_IOS(6_0);
    

    代码:

    [self.leftLB mas_makeConstraints:^(MASConstraintMaker *make) {
        make.height.equalTo(@(30));
        make.left.equalTo(self.view).offset(10);
        make.centerY.equalTo(self.view).offset(-50);
        make.right.mas_lessThanOrEqualTo(self.rightLB.mas_left);
    }];
        
    [self.rightLB mas_makeConstraints:^(MASConstraintMaker *make) {
        make.height.equalTo(@(30));
        make.left.mas_greaterThanOrEqualTo(self.leftLB.mas_right);
        make.right.equalTo(self.view).offset(-10);
        make.centerY.equalTo(self.leftLB);
    }];
        
    [self.leftLB1 mas_makeConstraints:^(MASConstraintMaker *make) {
        make.height.equalTo(@(30));
        make.left.equalTo(self.view).offset(10);
        make.centerY.equalTo(self.view).offset(50);
        make.right.mas_lessThanOrEqualTo(self.rightLB1.mas_left);
    }];
        
    [self.rightLB1 mas_makeConstraints:^(MASConstraintMaker *make) {
        make.height.equalTo(@(30));
        make.left.mas_greaterThanOrEqualTo(self.leftLB1.mas_right);
        make.right.equalTo(self.view).offset(-10);
        make.centerY.equalTo(self.leftLB1);
    }];
    
    //让左边的label抗压缩性降低,即可压缩,越高越不容易被压缩[self.leftLB1 setContentCompressionResistancePriority:UILayoutPriorityDefaultLow forAxis:UILayoutConstraintAxisHorizontal];
    /*
    或者让左边的label抗拉伸性增高,越高越不容易被拉伸
    [self.leftLB1 setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
    或者让右边的label抗压缩性增高,即可扩张
    [self.rightLB1 setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
    或者让右边的label抗拉伸性降低,即可扩张
    [self.rightLB1 setContentHuggingPriority:UILayoutPriorityDefaultLow forAxis:UILayoutConstraintAxisHorizontal];
    */
    
    

    更新:让一个控件既不被压缩也不被拉伸

    [label setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
    [label setContentCompressionResistancePriority:UILayoutPriorityDefaultHigh forAxis:UILayoutConstraintAxisHorizontal];
    

    最关键的注释那几句话,随便选中一句都可以达到效果。

    效果图

    最后:

    附加一个很好用的相似布局自动排列:

    [self.container addSubview:self.label1];
    [self.container addSubview:self.label2];
    [self.container addSubview:self.label3];
    //将控件添加到一个数组里面
    NSArray *array = @[self.label1,self.label2,self.label3]; 
    /*
    使用方法,一次性配置:横向布局,控件间距90,第一个控件与父容器间距15,
    最后一个控件与父容器间距15
    */
    [array mas_distributeViewsAlongAxis:MASAxisTypeHorizontal 
    withFixedSpacing:90 leadSpacing:15 tailSpacing:15];  
    
    //设置单个view的大小,在父view的与需要平分的方向的垂直方向的位置,例如需要在水平方向平分,就给一个竖直方向的位置
    [array mas_makeConstraints:^(MASConstraintMaker *make) {
      make.top.equalTo(@120);
      make.height.equalTo(@75);
    }];
    

    实现效果


    效果

    相关文章

      网友评论

          本文标题:iOS实战之从左往右自动填充布局页面

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