zoukankan      html  css  js  c++  java
  • IOS开发之自动布局框架设计(四)

    【上集剧情概要:上集我们主要实现了一个完整的自动布局的框架,这集我们主要研究下比较流行的开源布局框架Masonry的布局思路】

    我们先来看看是如何开始使用Masonry的,一般我们使用这个布局框架的时候,都会调用以下代码。。。。。

     [self.view1 mas_makeConstraints:^(MASConstraintMaker *make) {
            make.left.mas_equalTo(50);
            make.right.mas_equalTo(-50);
            make.top.mas_equalTo(50);
            make.bottom.mas_equalTo(-50);
        }];

    我们来分析下这段代码,UIView类型的使用了mas_makeConstraints这个方法,这个是写在分类里面的,有一个block参数,我们看一下里面的实现代码

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

    首先设置translatesAutoresizingMaskIntoConstraints属性为NO

    第二行初始化了一个MASConstraintMaker类,那这个类里面做了什么操作呢,好吧,本着刨根问底的精神我们继续往下看

    - (id)initWithView:(MAS_VIEW *)view {
        self = [super init];
        if (!self) return nil;
        
        self.view = view;
        self.constraints = NSMutableArray.new;
        
        return self;
    }

    将当前的view赋给maker类,然后初始化constraints,这是一个约束数组。

    我们仔细看block(constraintMaker);这一行代码。。。

    神马意思呢?

    首先这个block是(void(^)(MASConstraintMaker *))类型的一个参数,我们其实可以更改为其它名称,感觉用block就有点混淆。。。

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

    比如可以更改为上面的形式...

    这段代码的理解就是初始化了一个constraintMaker类,然后设置它的constraint属性,最后加载安装(install)

     [self.view1 mas_makeConstraints:^(MASConstraintMaker *make) {
            make.left.mas_equalTo(50);
            make.right.mas_equalTo(-50);
            make.top.mas_equalTo(50);
            make.bottom.mas_equalTo(-50);
        }];

    注意:这种写法很容易理解为这是一个block,但其实只是在执行一个函数,后面一大块只不过是函数的一个参数而已,只不过它的参数是一个函数。

    它等价与下面的一种写法:

    self.view1.translatesAutoresizingMaskIntoConstraints = NO;
    MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self.view1];
    constraintMaker.left.mas_equalTo(50);
    constraintMaker.right.mas_equalTo(-50);
    constraintMaker.top.mas_equalTo(50);
    constraintMaker.bottom.mas_equalTo(-50);
    [constraintMaker install];

    那这样写的话就不是很方便了,那么有什么办法吗???

    我们把它封装成一个函数???好的,封装成一个函数我们要做几件事情

    -(void)addMakeConstraints
    {
        //初始化MASConstraintMaker
        self.translatesAutoresizingMaskIntoConstraints = NO;
        MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
        
        //设置它的属性
      //  .........
        
        
        //加载
        [constraintMaker install];
    }

    那么第二步该怎么做呢?

    传参数???但是参数有很多呀??怎么办??

    比如我设置一个字典,里面用key,value来表示(left:50,right:-50,top:50,bottom:-50)好像也可以,但总觉的不是很方便

    -(void)addMakeConstraints:(NSMutableDictionary *)dictionary
    {
        //初始化MASConstraintMaker
        self.translatesAutoresizingMaskIntoConstraints = NO;
        MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
        
        //设置它的属性
      //  .........
        
        constraintMaker.left.mas_equalTo([dictionary[@"left"] intValue]);
        constraintMaker.right.mas_equalTo([dictionary[@"right"] intValue]);
        constraintMaker.top.mas_equalTo([dictionary[@"top"] intValue]);
        constraintMaker.bottom.mas_equalTo([dictionary[@"bottom"] intValue]);
        
        
        //加载
        [constraintMaker install];
    }
    NSMutableDictionary *constraint=[[NSMutableDictionary alloc]init];
    [constraint setObject:@"50" forKey:@"left"];
    [constraint setObject:@"-50" forKey:@"right"];
    [constraint setObject:@"50" forKey:@"top"];
    [constraint setObject:@"-50" forKey:@"bottom"]; 
    [self.view1 addMakeConstraints:constraint];
        

    貌似也可以实现的额,那有没有什么更好地办法呢?我们看下第一种写法:

    -(void)addMakeConstraints
    {
        //初始化MASConstraintMaker
        self.translatesAutoresizingMaskIntoConstraints = NO;
        MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
        
        //设置它的属性
      //  .........
        
        
        //加载
        [constraintMaker install];
    }

    其实我们中间就是缺了一段代码:那可以使用delegate吗

    -(void)addMakeConstraints
    {
        //初始化MASConstraintMaker
        self.translatesAutoresizingMaskIntoConstraints = NO;
        MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
        
        [self.del addConstraint:constraintMaker];
        
        
        //加载
        [constraintMaker install];
    }
    -(void)addConstraint:(MASConstraintMaker *)maker
    {
        maker.left.mas_equalTo(50);
        maker.right.mas_equalTo(-50);
        maker.top.mas_equalTo(50);
        maker.bottom.mas_equalTo(-50);
    }

    既然可以用代理实现,那么block肯定也是可以的

    好的,我们改装成block版本

    -(void)addMakeConstraints
    {
        //初始化MASConstraintMaker
        self.translatesAutoresizingMaskIntoConstraints = NO;
        MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
        
        self.makerBlock(constraintMaker);
       
        //加载
        [constraintMaker install];
    }
    [self.view1 addMakeConstraints];
    self.view1.makerBlock=^(MASConstraintMaker *maker){
          
            maker.left.mas_equalTo(50);
            maker.right.mas_equalTo(-50);
            maker.top.mas_equalTo(50);
            maker.bottom.mas_equalTo(-50);
            
    };

    在这里,我们是作为一个属性来使用block的,那么我们还可以直接用参数作为block来实现的。

    也就是说把这段代码封装成一个block参数

    -(void)addMakeConstraints:(void(^)(MASConstraintMaker *maker))maker
    {
        //初始化MASConstraintMaker
        self.translatesAutoresizingMaskIntoConstraints = NO;
        MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
        
        maker(constraintMaker);
       
        //加载
        [constraintMaker install];
    }
     [self.view1 addMakeConstraints:^(MASConstraintMaker *make)
        {
            make.left.mas_equalTo(50);
            make.right.mas_equalTo(-50);
            make.top.mas_equalTo(50);
            make.bottom.mas_equalTo(-50);
        }];

    至此,这段代码已经分析完毕,哈哈,总结就一句话:初始化MASConstraintMaker类,然后设置属性,最后加载,不同的就是将设置属性作为代码块调到实现的类里面来了而已。

    好的 我们看下View+MASAdditions类

    /**
     *    following properties return a new MASViewAttribute with current view and appropriate NSLayoutAttribute
     */
    @property (nonatomic, strong, readonly) MASViewAttribute *mas_left;
    @property (nonatomic, strong, readonly) MASViewAttribute *mas_top;
    @property (nonatomic, strong, readonly) MASViewAttribute *mas_right;
    @property (nonatomic, strong, readonly) MASViewAttribute *mas_bottom;
    @property (nonatomic, strong, readonly) MASViewAttribute *mas_leading;
    @property (nonatomic, strong, readonly) MASViewAttribute *mas_trailing;
    @property (nonatomic, strong, readonly) MASViewAttribute *mas_width;
    @property (nonatomic, strong, readonly) MASViewAttribute *mas_height;
    @property (nonatomic, strong, readonly) MASViewAttribute *mas_centerX;
    @property (nonatomic, strong, readonly) MASViewAttribute *mas_centerY;
    @property (nonatomic, strong, readonly) MASViewAttribute *mas_baseline;
    @property (nonatomic, strong, readonly) MASViewAttribute *(^mas_attribute)(NSLayoutAttribute attr);
    
    #if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 80000) || (__TV_OS_VERSION_MIN_REQUIRED >= 9000) || (__MAC_OS_X_VERSION_MIN_REQUIRED >= 101100)
    
    @property (nonatomic, strong, readonly) MASViewAttribute *mas_firstBaseline;
    @property (nonatomic, strong, readonly) MASViewAttribute *mas_lastBaseline;
    
    #endif
    
    #if TARGET_OS_IPHONE || TARGET_OS_TV
    
    @property (nonatomic, strong, readonly) MASViewAttribute *mas_leftMargin;
    @property (nonatomic, strong, readonly) MASViewAttribute *mas_rightMargin;
    @property (nonatomic, strong, readonly) MASViewAttribute *mas_topMargin;
    @property (nonatomic, strong, readonly) MASViewAttribute *mas_bottomMargin;
    @property (nonatomic, strong, readonly) MASViewAttribute *mas_leadingMargin;
    @property (nonatomic, strong, readonly) MASViewAttribute *mas_trailingMargin;
    @property (nonatomic, strong, readonly) MASViewAttribute *mas_centerXWithinMargins;
    @property (nonatomic, strong, readonly) MASViewAttribute *mas_centerYWithinMargins;

    这一段是对MASViewAttribute的声明,看它的名字就知道这一段是对NSLayoutAttribute的封装,我们知道NSLayoutAttribute只是一些属性的枚举,那么封装有什么意义呢?

    好吧,我们看下这段代码:

     [self.view2 mas_makeConstraints:^(MASConstraintMaker *make) {
            make.top.mas_equalTo(self.view1.mas_bottom).offset(10);
    }];

    有个self.view1.mas_bottom,我们知道要设置这个属性的话,要使用原生的方法:

    NSLayoutConstraint *constaint=[NSLayoutConstraint constraintWithItem:self
                                                                           attribute:att
                                                                           relatedBy:NSLayoutRelationEqual
                                                                              toItem:attribute.view
                                                                           attribute:attribute.attribute
                                                                          multiplier:1.0
                                                                            constant:space];

    在这里有个toItem,那要设置toItem就必须知道当前是哪个view,如果只有NSLayoutAttribute属性的话,这段代码中得toItem是设置不了的。

    所以MASViewAttribute便添加了view这个属性,方便这个地方的设置MAS---View---Attribute,可以这么理解,哈哈!

    /**
     *  Creates a MASConstraintMaker with the callee view.
     *  Any constraints defined are added to the view or the appropriate superview once the block has finished executing
     *
     *  @param block scope within which you can build up the constraints which you wish to apply to the view.
     *
     *  @return Array of created MASConstraints
     */
    - (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *make))constraintMakerblock;
    
    /**
     *  Creates a MASConstraintMaker with the callee view.
     *  Any constraints defined are added to the view or the appropriate superview once the block has finished executing.
     *  If an existing constraint exists then it will be updated instead.
     *
     *  @param block scope within which you can build up the constraints which you wish to apply to the view.
     *
     *  @return Array of created/updated MASConstraints
     */
    - (NSArray *)mas_updateConstraints:(void(^)(MASConstraintMaker *make))block;
    
    /**
     *  Creates a MASConstraintMaker with the callee view.
     *  Any constraints defined are added to the view or the appropriate superview once the block has finished executing.
     *  All constraints previously installed for the view will be removed.
     *
     *  @param block scope within which you can build up the constraints which you wish to apply to the view.
     *
     *  @return Array of created/updated MASConstraints
     */
    - (NSArray *)mas_remakeConstraints:(void(^)(MASConstraintMaker *make))block;

    这几个方法分别是添加约束,更新约束以及注销约束,前面已经将mas_makeConstraints这个方法讲的很详细了,后面两个方法类似。

    只不过多了两个变量来控制:constraintMaker.updateExisting = YES;constraintMaker.removeExisting = YES;

    好的,我们接着向下看:

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

    第一步:将maker的view设置为当前view

    第二步:设置属性

    第三步:加载

    我们看下第二步:

    make.left.mas_equalTo(50);
    make.right.mas_equalTo(-50);
    make.top.mas_equalTo(50);
    make.bottom.mas_equalTo(-50);

    第二步用的链式结构,如果不懂得话可以看看我之前的文章。

    make.left返回的MASConstraint类型

    - (MASConstraint * (^)(id attr))mas_equalTo;
    - (MASConstraint * (^)(id attr))mas_greaterThanOrEqualTo;
    - (MASConstraint * (^)(id attr))mas_lessThanOrEqualTo;
    - (MASConstraint * (^)(id))mas_equalTo {
        return ^id(id attribute) {
            return self.equalToWithRelation(attribute, NSLayoutRelationEqual);
        };
    }

    然后执行mas_equalTo的方法:

    它的返回值是:MASConstraint * (^)(id) 一个block

  • 相关阅读:
    Qt 字符串QString arg()用法总结
    Qt子窗口QMidSubwindow全屏出现的问题总结
    QString介绍
    Qt控制台输出QString
    汽车辐射监测系统-Qt开发[转]发
    Eclipse Qt开发环境的建立
    串口调节工具
    QT 多线程程序设计 -互斥
    ArcGIS Spatial Query
    IQueryFielter接口
  • 原文地址:https://www.cnblogs.com/guchengfengyun/p/5856982.html
Copyright © 2011-2022 走看看