iOS Masonry—最优美的自动布局框架-实现原理

2017-06-19  本文已影响0人  Onlyoner

在做需求的时候为了完美的适配各种尺寸的屏幕,我们往往需要做大量的适配工作,有了Masonry之后使我们的适配工作减轻了不少,出了Masonry还有一个优秀的框架国内SDAutoLayout

小对比:

UIView *view = UIView.new;
[self.view addSubview:view]
SDAutoLayout:
view.sd_layout.leftSpaceToView(self.view, 20).bottomSpaceToView(self.view, 20).widthIs(100).heightIs(100);
Masonry:
[view mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.offset(20);
        make.top.offset(100);
        make.height.equalTo(@100);
        make.right.equalTo(view1.mas_left).with.offset(-100);
}];
我们项目中两种都有使用,各有千秋结合起来更能事半功倍:

下边从Masonry说起:

集成框架到项目【cocoaPods】【直接将文件夹拖入】两种方式
#import "ViewController.h"
#import "Masonry.h"
@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    
    //1⃣️创建一个上下左右距离10的view
    UIView *redview = [[UIView alloc] init];
    redview.backgroundColor = [UIColor redColor];
    [self.view addSubview:redview];
    //2⃣️添加约束
    //make 约束制造者
    /*
     补充小知识:
     10不是对象,加个@10,会将其转化成对象[NSNumber numberWithInt:10],@就是一种简便写法,
     如@[]代表数组,@{}代表NSDictionary
     */
  
    [redview mas_makeConstraints:^(MASConstraintMaker *make) {
    
        make.left.top.equalTo(@10);
        
        make.bottom.right.equalTo(@-10);
        
        /*
         mas_makeConstraints执行流程:
         1、创建约束制造者 MASConstraintMaker 并且绑定控件
         2、执行mas_makeConstraints传入的Block
         3、让约束制造者安装约束
         *3.1、清空之前所有约束
         * 3.2、遍历约束数组,一个一个安装
         */
    }];
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


@end

Simulator Screen Shot 2017年6月19日 下午7.07.50.png

实现原理也就是 mas_makeConstraints执行流程:

mas_makeConstraints:

" cmd "点"mas_makeConstraints"进去
" [redview mas_makeConstraints:^(MASConstraintMaker *make) {}]"

创建约束制造者 MASConstraintMaker 并且绑定控件

- (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *))block {
    self.translatesAutoresizingMaskIntoConstraints = NO;
    MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
    block(constraintMaker);
    return [constraintMaker install];
}

执行mas_makeConstraints传入的Block

block(constraintMaker);

把MASConstraintMaker传过去其实就是make
让约束制造者安装约束

[constraintMaker install]安装约束

一进去就去清空之前所有约束

- (NSArray *)install {
    if (self.removeExisting) {
        NSArray *installedConstraints = [MASViewConstraint installedConstraintsForView:self.view];
        for (MASConstraint *constraint in installedConstraints) {
            [constraint uninstall];
        }
    }
    NSArray *constraints = self.constraints.copy;
    for (MASConstraint *constraint in constraints) {
        constraint.updateExisting = self.updateExisting;
        [constraint install];
    }
    [self.constraints removeAllObjects];
    return constraints;
}

遍历约束数组,一个一个安装

MASViewConstraint
[constraint install]
- (void)install {
    if (self.hasBeenInstalled) {
        return;
    }
    
    if ([self supportsActiveProperty] && self.layoutConstraint) {
        self.layoutConstraint.active = YES;
        [self.firstViewAttribute.view.mas_installedConstraints addObject:self];
        return;
    }
    
    MAS_VIEW *firstLayoutItem = self.firstViewAttribute.item;
    NSLayoutAttribute firstLayoutAttribute = self.firstViewAttribute.layoutAttribute;
    MAS_VIEW *secondLayoutItem = self.secondViewAttribute.item;
    NSLayoutAttribute secondLayoutAttribute = self.secondViewAttribute.layoutAttribute;

    // alignment attributes must have a secondViewAttribute
    // therefore we assume that is refering to superview
    // eg make.left.equalTo(@10)
    if (!self.firstViewAttribute.isSizeAttribute && !self.secondViewAttribute) {
        secondLayoutItem = self.firstViewAttribute.view.superview;
        secondLayoutAttribute = firstLayoutAttribute;
    }
    
    MASLayoutConstraint *layoutConstraint
        = [MASLayoutConstraint constraintWithItem:firstLayoutItem
                                        attribute:firstLayoutAttribute
                                        relatedBy:self.layoutRelation
                                           toItem:secondLayoutItem
                                        attribute:secondLayoutAttribute
                                       multiplier:self.layoutMultiplier
                                         constant:self.layoutConstant];
    
    layoutConstraint.priority = self.layoutPriority;
    layoutConstraint.mas_key = self.mas_key;
    
    if (self.secondViewAttribute.view) {
        MAS_VIEW *closestCommonSuperview = [self.firstViewAttribute.view mas_closestCommonSuperview:self.secondViewAttribute.view];
        NSAssert(closestCommonSuperview,
                 @"couldn't find a common superview for %@ and %@",
                 self.firstViewAttribute.view, self.secondViewAttribute.view);
        self.installedView = closestCommonSuperview;
    } else if (self.firstViewAttribute.isSizeAttribute) {
        self.installedView = self.firstViewAttribute.view;
    } else {
        self.installedView = self.firstViewAttribute.view.superview;
    }


    MASLayoutConstraint *existingConstraint = nil;
    if (self.updateExisting) {
        existingConstraint = [self layoutConstraintSimilarTo:layoutConstraint];
    }
    if (existingConstraint) {
        // just update the constant
        existingConstraint.constant = layoutConstraint.constant;
        self.layoutConstraint = existingConstraint;
    } else {
        [self.installedView addConstraint:layoutConstraint];
        self.layoutConstraint = layoutConstraint;
        [firstLayoutItem.mas_installedConstraints addObject:self];
    }
}
这一堆就是Masonry帮我们写的自动布局的代码,这段相当恶心,把它藏在这里,以后调用的时候就不用写这段代码了。
至此自动布局的安装完成所有的约束

那么什么是链式编程思想?

链式编程的思想:方法的返回值必须要有 “方法调用者”

才能一直点"."下去


 [redview mas_makeConstraints:^(MASConstraintMaker *make) {
        //设置约束 每次调用left/top就是将约束添加到数组中
      /*  
        make.left.top.equalTo(@10);
        
        make.bottom.right.equalTo(@-10);
        */
以上这两句就相当于下边:
         MASConstraint * (^block)(id) = make.top.left.equalTo;
         MASConstraint *mk = block(@10);
         mk.left.top.equalTo(@10);
        

     
    }];
上一篇下一篇

猜你喜欢

热点阅读