美文网首页适配
Masonry&snapKit使用详解

Masonry&snapKit使用详解

作者: AntKing | 来源:发表于2017-08-19 10:02 被阅读38次

Masonry地址demo

https://github.com/HongXiuTanXiang/Masonry-.git

snapKit地址demo
https://github.com/HongXiuTanXiang/snapKit-.git

snapKit是swift版的Masonry,使用方法基本一致,学会Masonry,也就会用另个一了,以Masonry为例讲解

使用Masonry之前可以先导入两个宏,这样开发起来更方便些

//1. 使用全局宏定义, 可以在调用masonry方法的时候不使用mas_前缀
#define MAS_SHORTHAND

//2. 可以使equalTo等效于mas_equalTo
#define MAS_SHORTHAND_GLOBALS

//导入头文件前先定义上面两个宏
#import "Masonry.h"

Masonry常用的几种方式

四约法


    UIView *containerView = [[UIView alloc]init];
    containerView.backgroundColor = [UIColor cyanColor];
    [self.view addSubview:containerView];
    UIEdgeInsets  padding = UIEdgeInsetsMake(10, 10, 10, 10);

    //用法1,四约法
    [containerView mas_makeConstraints:^(MASConstraintMaker *make) {
        
        make.left.equalTo(self.view.left).and.offset(padding.left);
        make.right.equalTo(self.view.right).and.offset(-padding.right);
        make.bottom.equalTo(self.view.bottom).and.offset(-padding.bottom);
        //
        make.height.equalTo(200);
        
        
    }];

边约法

   
    //用法2,边约法
    UIView *redview = [UIView new];
    _redView = redview;
    redview.backgroundColor = [UIColor redColor];
    [containerView addSubview:redview];
    [redview mas_makeConstraints:^(MASConstraintMaker *make) {
        
//        make.edges.equalTo(containerView).insets(padding);
        //简写,现在可以大胆的使用equalTo了
        make.edges.equalTo(padding);

    }];
    

中心约束加size

    KKButton *btn1 = [[KKButton alloc]init];
    _btn = btn1;
    [btn1 addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];
    [btn1 setTitle:@"点我啊" forState:UIControlStateNormal];
    [btn1 setBackgroundImage:[self imageWithColor:[UIColor greenColor]] forState:UIControlStateNormal];
    [redview addSubview:btn1];
    
    [btn1 makeConstraints:^(MASConstraintMaker *make) {
        
        make.center.equalTo(redview.center);
        make.size.equalTo(redview).and.sizeOffset(CGSizeMake(-20, -20));
    }];
    

首尾间距固定且等间距,控件的宽度变化

    //首先添加5个视图
    NSMutableArray *array = [NSMutableArray new];
    for (int i = 0; i < 5; i ++) {
        UIView *view = [UIView new];
        view.backgroundColor = [UIColor greenColor];
        [self.view addSubview:view];
        [array addObject:view]; //保存添加的控件
    }
    
    //水平首尾固定等间距,
    [array mas_distributeViewsAlongAxis:MASAxisTypeHorizontal withFixedSpacing:15.0 leadSpacing:10.0 tailSpacing:10.0];
    [array mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(self.view.top).and.offset(100);
        make.height.equalTo(60);
    }];

首尾间距固定,控件宽度固定,间距变化

    //首先添加5个视图
    NSMutableArray *array = [NSMutableArray new];
    for (int i = 0; i < 5; i ++) {
        UIView *view = [UIView new];
        view.backgroundColor = [UIColor blueColor];
        [self.view addSubview:view];
        [array addObject:view]; //保存添加的控件
    }
    
    [array mas_distributeViewsAlongAxis:MASAxisTypeHorizontal withFixedItemLength:40.0 leadSpacing:10 tailSpacing:10];
    [array mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(self.view).with.offset(300);
        make.height.equalTo(60);
    }];
    

多行Label问题

    //创建label
    UILabel *label = [[UILabel alloc]init];
    _label = label;
    self.label.numberOfLines = 0;
    _label.textAlignment = NSTextAlignmentCenter;
    self.label.backgroundColor = [UIColor redColor];
    self.label.lineBreakMode = NSLineBreakByTruncatingTail;
    self.label.text = @"OpenGL存储它的所有深度信息于一个Z缓冲(Z-buffer)中,也被称为深度缓冲(Depth Buffer)。GLFW会自动为你生成这样一个缓冲(就像它也有一个颜色缓冲来存储输出图像的颜色)。深度值存储在每个片段里面(作为片段的z值),当片段想要输出它的颜色时,OpenGL会将它的深度值和z缓冲进行比较,如果当前的片段在其它片段之后,它将会被丢弃,否则将会覆盖。这个过程称为深度测试(Depth Testing),它是由OpenGL自动完成的。然而,如果我们想要确定OpenGL真的执行了深度测试,首先我们要告诉OpenGL我们想要启用深度测试;它默认是关闭的。我们可以通过glEnable函数来开启深度测试。glEnable和glDisable函数允许我们启用或禁用某个OpenGL功能。这个功能会一直保持启用/禁用状态,直到另一个调用来禁用/启用它。现在我们想启用深度测试,需要开启GL_DEPTH_TEST:";
    [self.view addSubview:label];
    
    self.label.textColor = [UIColor blackColor];
    
    [label makeConstraints:^(MASConstraintMaker *make) {
       
        make.left.top.equalTo(20);
        make.right.equalTo(-20);
    }];
    

scrollView使用自动布局

 //创建滚动视图
    UIScrollView *scrollView = [UIScrollView new];
    self.scrollView = scrollView;
    
    scrollView.backgroundColor = [UIColor grayColor];
    [self.view addSubview:scrollView];
    
    [self.scrollView makeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(self.view);
    }];
    
    //约束UIScrollView上contentView
    UIView *contentView = [UIView new];
    [self.scrollView addSubview:contentView];
    
    [contentView makeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(self.scrollView);
//        make.width.equalTo(200);
//        make.width.equalTo(1000);
        make.width.equalTo(300);
        
    }];
    
    

    
    //添加控件到contentView,约束原理与自动布局相同
    UIView *lastView;
    CGFloat height = 30;
    for (int i = 0; i <15; i ++) {
        UIView *view = UIView.new;
        view.backgroundColor = [UIColor colorWithRed:arc4random() % 255 / 256.0  green:arc4random() % 255 / 256.0 blue:arc4random() % 255 / 256.0 alpha:1.0];
        [contentView addSubview:view];
        
        [view makeConstraints:^(MASConstraintMaker *make) {
            make.top.equalTo(lastView ? lastView.bottom : @0);
            make.left.equalTo(0);
            make.width.equalTo(800);
            make.height.equalTo(height);
        }];
        
        height += 30;
        lastView = view;
    }
    
    
    //最后再改变一下 容器view的底部约束,这样就确定了scorllView的滚动范围了;
    [contentView makeConstraints:^(MASConstraintMaker *make) {
        make.bottom.equalTo(lastView.bottom);
    }];


使用priority(优先级)做动画

    // 红色View
    UIView *redView = [[UIView alloc]init];
    redView.backgroundColor = [UIColor redColor];
    [self.view addSubview:redView];
    // 蓝色View
    self.blueView = [[UIView alloc]init];
    self.blueView.backgroundColor = [UIColor blueColor];
    [self.view addSubview:self.blueView];
    // 黄色View
    UIView *yellowView = [[UIView alloc]init];
    yellowView.backgroundColor = [UIColor yellowColor];
    [self.view addSubview:yellowView];
    // ---红色View--- 添加约束
    [redView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.mas_equalTo(self.view.mas_left).with.offset(20);
        make.bottom.mas_equalTo(self.view.mas_bottom).with.offset(-80);
        make.height.equalTo([NSNumber numberWithInt:50]);
    }];
    // ---蓝色View--- 添加约束
    [self.blueView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.mas_equalTo(redView.mas_right).with.offset(40);
        make.bottom.width.height.mas_equalTo(redView);
    }];
    // ---黄色View--- 添加约束
    [yellowView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.mas_equalTo(self.blueView.mas_right).with.offset(40);
        make.right.mas_equalTo(self.view.mas_right).with.offset(-20);
        make.bottom.width.height.mas_equalTo(redView);
        // 优先级设置为250,最高1000(默认)
        make.left.mas_equalTo(redView.mas_right).with.offset(20).priority(250);
    }];

// 点击屏幕移除蓝色View
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self.blueView removeFromSuperview];
    [UIView animateWithDuration:1.0 animations:^{
        [self.view layoutIfNeeded];
    }];
}

这里解释:这里的三个View的宽度是根据约束自动推断设置的,对黄色的View设置了一个与红色View有关的priority(250)的优先级,它同时有对蓝色View有个最高的优先级约束(make.left.mas_equalTo(self.blueView.mas_right).with.offset(40);)。当点击屏幕是,我将蓝色View移除,此时第二优先级就是生效。

更新约束mas_updateConstraints


- (void)createGrowingButton {
    self.growingButton = [UIButton buttonWithType:UIButtonTypeSystem];
    [self.growingButton setTitle:@"点我放大" forState:UIControlStateNormal];
    self.growingButton.layer.borderColor = UIColor.greenColor.CGColor;
    self.growingButton.layer.borderWidth = 3;
    [self.growingButton addTarget:self action:@selector(onGrowButtonTaped:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:self.growingButton];
    self.scacle = 1.0;
    [self.growingButton mas_makeConstraints:^(MASConstraintMaker *make) {
        make.center.mas_equalTo(self.view);
        // 初始宽、高为100,优先级最低
        make.width.height.mas_equalTo(100 * self.scacle);
        // 最大放大到整个view
        make.width.height.lessThanOrEqualTo(self.view);
    }];
}

- (void)onGrowButtonTaped:(UIButton *)sender {
    self.scacle += 1.0;
    // 告诉self.view约束需要更新
    [self.view setNeedsUpdateConstraints];
    // 调用此方法告诉self.view检测是否需要更新约束,若需要则更新,下面添加动画效果才起作用
    [self.view updateConstraintsIfNeeded];
    [UIView animateWithDuration:0.3 animations:^{
        [self.view layoutIfNeeded];
    }];
}


// 重写该方法来更新约束,这个方法系统自动调用,使用autolayout之后,系统在view显示之前,
或则有需要更新约束的时候,都会来调用这个方法,需要更新的约束都写到这个方法里就可以了,
最后不要忘记调用super,如果很多地方需要更新,可以加一些条件判断,这样就根据条件去更新对应的内容
- (void)updateViewConstraints {
    [self.growingButton mas_updateConstraints:^(MASConstraintMaker *make) {
        // 这里写需要更新的约束,不用更新的约束将继续存在
        // 不会被取代,如:其宽高小于屏幕宽高不需要重新再约束
        make.width.height.mas_equalTo(20 * self.scacle);
    }];
    [super updateViewConstraints];
}

重写约束mas_remakeConstraints

- (void)createExpandButton {
    self.isExpanded = NO;
    self.growingButton = [UIButton buttonWithType:UIButtonTypeSystem];
    [self.growingButton setTitle:@"点我展开" forState:UIControlStateNormal];
    self.growingButton.layer.borderColor = UIColor.greenColor.CGColor;
    self.growingButton.layer.borderWidth = 3;
    self.growingButton.backgroundColor = [UIColor redColor];
    [self.growingButton addTarget:self action:@selector(onGrowButtonTaped:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:self.growingButton];
    [self.growingButton mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.mas_equalTo(0);
        make.left.right.mas_equalTo(0);
        make.bottom.mas_equalTo(-350);
    }];
}



- (void)onGrowButtonTaped:(UIButton *)sender {
//    self.scacle += 1.0;
//    // 告诉self.view约束需要更新
//    [self.view setNeedsUpdateConstraints];
//    // 调用此方法告诉self.view检测是否需要更新约束,若需要则更新,下面添加动画效果才起作用
//    [self.view updateConstraintsIfNeeded];
//    [UIView animateWithDuration:0.3 animations:^{
//        [self.view layoutIfNeeded];
//    }];
    
    self.isExpanded = !self.isExpanded;
    if (!self.isExpanded) {
        [self.growingButton setTitle:@"点我展开" forState:UIControlStateNormal];
    } else {
        [self.growingButton setTitle:@"点我收起" forState:UIControlStateNormal];
    }
    // 告诉self.view约束需要更新
    [self.view setNeedsUpdateConstraints];
    // 调用此方法告诉self.view检测是否需要更新约束,若需要则更新,下面添加动画效果才起作用
    [self.view updateConstraintsIfNeeded];
    [UIView animateWithDuration:0.3 animations:^{
        [self.view layoutIfNeeded];
    }];
}



- (void)updateViewConstraints {
//    [self.growingButton mas_updateConstraints:^(MASConstraintMaker *make) {
//        // 这里写需要更新的约束,不用更新的约束将继续存在
//        // 不会被取代,如:其宽高小于屏幕宽高不需要重新再约束
//        make.width.height.mas_equalTo(20 * self.scacle);
//    }];
//    [super updateViewConstraints];
    
    
    // 这里使用update也能实现效果
    // remake会将之前的全部移除,然后重新添加
    __weak __typeof(self) weakSelf = self;
    [self.growingButton mas_remakeConstraints:^(MASConstraintMaker *make) {
        // 这里重写全部约束,之前的约束都将失效
        make.top.mas_equalTo(0);
        make.left.right.mas_equalTo(0);
        if (weakSelf.isExpanded) {
            make.bottom.mas_equalTo(0);
        } else {
            make.bottom.mas_equalTo(-350);
        }
    }];
    [super updateViewConstraints];
}

mas_remakeConstraints和 mas_updateConstraints 的区别在于前者重新对视图进行了约束(抛弃了之前的约束),后者是更新约束条件(保留未更新的约束,如:这次更新了对 height 的约束,其他对X&Y以及宽的约束不变)。

相关文章

网友评论

  • 舒马赫:Masory写的很棒,但是不喜欢纯代码写界面,太慢了,另外由于autolayout先天原因布局速度是比较慢的,会影响帧率。推荐使用xml的布局库FlexLib,采用前端布局标准flexbox(不使用autolayout),支持热刷新,自动计算高度等。可以到这里了解详细信息:

    https://github.com/zhenglibao/FlexLib

本文标题:Masonry&snapKit使用详解

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