iOS Masonry实现九宫格布局

作者: 鬼丶白 | 来源:发表于2018-03-19 17:15 被阅读162次

    直接复制下面代码看效果
    一、常规布局方式


    517349-20160819194720781-2023804629.png 517349-20160819194712937-1138283651.png 517349-20160819194657703-1828190789.png
    - (void)viewDidLoad {
        [super viewDidLoad];
        // TODO: 创建一个装载九宫格的容器
        UIView *containerView = [[UIView alloc] init];
        [self.view addSubview:containerView];
        containerView.backgroundColor = [UIColor whiteColor];
        containerView.layer.borderWidth = 1;
        containerView.layer.borderColor = [UIColor grayColor].CGColor;
        
       // TODO:给该容器添加布局代码
        [containerView makeConstraints:^(MASConstraintMaker *make) {
            make.left.equalTo(15);
            make.top.equalTo(66);
            make.right.equalTo(-15);
            make.height.equalTo(300);
        }];
    
        // TODO:  为该容器添加宫格View 
        for (int i = 0; i < 10; i++) {
            UIView *view = [[UIView alloc] init];
            view.backgroundColor = [UIColor randomColor];
            [containerView addSubview:view];
        }
    
        // TODO: 执行九宫格布局
    
       /*
         一行代码,就可以实现九宫格布局
         
         -[NSArray mas_distributeSudokuViewsWithFixedItemWidth:fixedItemHeight:fixedLineSpacing:fixedInteritemSpacing:warpCount:topSpacing:bottomSpacing:leadSpacing:tailSpacing:]
         
         参数介绍:
         
         fixedItemWidth: 宫格的宽度,如果设置为0的话,则由父容器控制宽度,如果不为零,则可以控制父容器的宽度
         
         fixedItemHeight:与fixedItemWidth同理
         
         fixedLineSpacing:宫格之间行的间距,如果宫格只有一行,则不生效
         
         fixedInteritemSpacing:宫格之间列的间距,如果只有一列,则不生效
         
         warpCount:折行的位置,如果设置为3,则表示该九宫格需要布局3列,值得一提的是,如果NSArray本身的count如果小于warpCount,则该函数会用空的UIView填充到缺失区域。
         
         topSpacing:bottomSpacing:leadSpacing:tailSpacing:九宫格顶边距,底边距,左边距以及右边距
         */
    
      [containerView.subviews  mas_distributeSudokuViewsWithFixedItemWidth:0
                                                            fixedItemHeight:0
                                                           fixedLineSpacing:10
                                                      fixedInteritemSpacing:20
                                                                  warpCount:3
                                                                 topSpacing:10
                                                              bottomSpacing:10
                                                                leadSpacing:10
                                                                tailSpacing:10];
        
    }
    

    二、另外一种布局方式

    517349-20160819200905937-430060348.png

    view创建代码不变 masnory实现代码如下

    /**
     *  九宫格布局 固定ItemSize 可变ItemSpacing
     *
     *  @param fixedItemWidth  固定宽度
     *  @param fixedItemHeight 固定高度
     *  @param warpCount       折行点
     *  @param topSpacing      顶间距
     *  @param bottomSpacing   底间距
     *  @param leadSpacing     左间距
     *  @param tailSpacing     右间距
     */
    /*
    - (void)mas_distributeSudokuViewsWithFixedItemWidth:(CGFloat)fixedItemWidth
                                        fixedItemHeight:(CGFloat)fixedItemHeight
                                              warpCount:(NSInteger)warpCount
                                             topSpacing:(CGFloat)topSpacing
                                          bottomSpacing:(CGFloat)bottomSpacing
                                            leadSpacing:(CGFloat)leadSpacing
                                            tailSpacing:(CGFloat)tailSpacing;
     */
    [containerView.subviews mas_distributeSudokuViewsWithFixedItemWidth:50
                                                           fixedItemHeight:50
                                                                 warpCount:3
                                                                topSpacing:10
                                                             bottomSpacing:10
                                                               leadSpacing:10
                                                               tailSpacing:10];
    

    // !!!: 实现如下 给数组加一个扩展

    .h

    #import "MASUtilities.h"
    #import "MASConstraintMaker.h"
    #import "MASViewAttribute.h"
    
    @interface NSArray (Sudoku)
    
    
    /**
     *  九宫格布局 固定ItemSize 可变ItemSpacing
     *
     *  @param fixedItemWidth  固定宽度
     *  @param fixedItemHeight 固定高度
     *  @param warpCount       折行点
     *  @param topSpacing      顶间距
     *  @param bottomSpacing   底间距
     *  @param leadSpacing     左间距
     *  @param tailSpacing     右间距
     */
    - (void)mas_distributeSudokuViewsWithFixedItemWidth:(CGFloat)fixedItemWidth
                                        fixedItemHeight:(CGFloat)fixedItemHeight
                                              warpCount:(NSInteger)warpCount
                                             topSpacing:(CGFloat)topSpacing
                                          bottomSpacing:(CGFloat)bottomSpacing
                                            leadSpacing:(CGFloat)leadSpacing
                                            tailSpacing:(CGFloat)tailSpacing;
    
    
    /**
     *  九宫格布局 可变ItemSize 固定ItemSpacing
     *
     *  @param fixedLineSpacing      行间距
     *  @param fixedInteritemSpacing 列间距
     *  @param warpCount             折行点
     *  @param topSpacing            顶间距
     *  @param bottomSpacing         底间距
     *  @param leadSpacing           左间距
     *  @param tailSpacing           右间距
     */
    - (void)mas_distributeSudokuViewsWithFixedLineSpacing:(CGFloat)fixedLineSpacing
                                    fixedInteritemSpacing:(CGFloat)fixedInteritemSpacing
                                                warpCount:(NSInteger)warpCount
                                               topSpacing:(CGFloat)topSpacing
                                            bottomSpacing:(CGFloat)bottomSpacing
                                              leadSpacing:(CGFloat)leadSpacing
                                              tailSpacing:(CGFloat)tailSpacing;
    
    
    /**
     *  九宫格布局 固定ItemSize 固定ItemSpacing
     *  可由九宫格的内容控制SuperView的大小
     *  如果warpCount大于[self count],该方法将会用空白的View填充到superview中
     *
     *  Sudoku Layout, has fixed item size, and fix item space
     *  If warp count greater than self.count, It's fill empty view to superview
     *
     *  @param fixedItemWidth        固定宽度,如果设置成0,则表示自适应,If set it to zero, indicates the adaptive.
     *  @param fixedItemHeight       固定高度,如果设置成0,则表示自适应,If set it to zero, indicates the adaptive.
     *  @param fixedLineSpacing      行间距
     *  @param fixedInteritemSpacing 列间距
     *  @param warpCount             折行点
     *  @param topSpacing            顶间距
     *  @param bottomSpacing         底间距
     *  @param leadSpacing           左间距
     *  @param tailSpacing           右间距
     *
     *  @return 一般情况下会返回[self copy], 如果warpCount大于[self count],则会返回一个被空白view填充过的数组,可以让你循环调用removeFromSuperview或者干一些其他的事情;
     *  @return Normal will return [self copy], If warpCount bigger than [self count] , It will return a empty views filled array, you could enumerate [subview removeFromSuperview] or do other things;
     */
    - (NSArray *)mas_distributeSudokuViewsWithFixedItemWidth:(CGFloat)fixedItemWidth
                                             fixedItemHeight:(CGFloat)fixedItemHeight
                                            fixedLineSpacing:(CGFloat)fixedLineSpacing
                                       fixedInteritemSpacing:(CGFloat)fixedInteritemSpacing
                                                   warpCount:(NSInteger)warpCount
                                                  topSpacing:(CGFloat)topSpacing
                                               bottomSpacing:(CGFloat)bottomSpacing
                                                 leadSpacing:(CGFloat)leadSpacing
                                                 tailSpacing:(CGFloat)tailSpacing;
    @end
    
    

    .m

    #import "NSArray+Sudoku.h"
    #import "View+MASAdditions.h"
    
    @implementation NSArray (Sudoku)
    
    
    - (MAS_VIEW *)star_commonSuperviewOfViews {
        
        if (self.count == 1) {
            return ((MAS_VIEW *)self.firstObject).superview;
        }
        
        MAS_VIEW *commonSuperview = nil;
        MAS_VIEW *previousView = nil;
        for (id object in self) {
            if ([object isKindOfClass:[MAS_VIEW class]]) {
                MAS_VIEW *view = (MAS_VIEW *)object;
                if (previousView) {
                    commonSuperview = [view mas_closestCommonSuperview:commonSuperview];
                } else {
                    commonSuperview = view;
                }
                previousView = view;
            }
        }
        NSAssert(commonSuperview, @"Can't constrain views that do not share a common superview. Make sure that all the views in this array have been added into the same view hierarchy.");
        return commonSuperview;
    }
    
    
    
    - (void)mas_distributeSudokuViewsWithFixedItemWidth:(CGFloat)fixedItemWidth
                                        fixedItemHeight:(CGFloat)fixedItemHeight
                                              warpCount:(NSInteger)warpCount
                                             topSpacing:(CGFloat)topSpacing
                                          bottomSpacing:(CGFloat)bottomSpacing
                                            leadSpacing:(CGFloat)leadSpacing
                                            tailSpacing:(CGFloat)tailSpacing {
        if (self.count < 2) {
            NSAssert(self.count>1,@"views to distribute need to bigger than one");
            return;
        }
        if (warpCount < 1) {
            NSAssert(false, @"warp count need to bigger than zero");
            return;
        }
        
        MAS_VIEW *tempSuperView = [self star_commonSuperviewOfViews];
        
        NSInteger rowCount = self.count % warpCount == 0 ? self.count / warpCount : self.count / warpCount + 1;
        
        MAS_VIEW *prev;
        for (int i = 0; i < self.count; i++) {
            
            MAS_VIEW *v = self[i];
            
            // 当前行
            NSInteger currentRow = i / warpCount;
            // 当前列
            NSInteger currentColumn = i % warpCount;
            
            [v mas_makeConstraints:^(MASConstraintMaker *make) {
                // 固定宽度
                make.width.equalTo(@(fixedItemWidth));
                make.height.equalTo(@(fixedItemHeight));
                
                // 第一行
                if (currentRow == 0) {
                    make.top.equalTo(tempSuperView).offset(topSpacing);
                }
                // 最后一行
                if (currentRow == rowCount - 1) {
                    make.bottom.equalTo(tempSuperView).offset(-bottomSpacing);
                }
                // 中间的若干行
                if (currentRow != 0 && currentRow != rowCount - 1){
                    CGFloat offset = (1-(currentRow/((CGFloat)rowCount-1)))*(fixedItemHeight+topSpacing)-currentRow*bottomSpacing/(((CGFloat)rowCount-1));
                    make.bottom.equalTo(tempSuperView).multipliedBy(currentRow/((CGFloat)rowCount-1)).offset(offset);
                }
                
                // 第一列
                if (currentColumn == 0) {
                    make.left.equalTo(tempSuperView).offset(leadSpacing);
                }
                // 最后一列
                if (currentColumn == warpCount - 1) {
                    make.right.equalTo(tempSuperView).offset(-tailSpacing);
                }
                // 中间若干列
                if (currentColumn != 0 && currentColumn != warpCount - 1) {
                    CGFloat offset = (1-(currentColumn/((CGFloat)warpCount-1)))*(fixedItemWidth+leadSpacing)-currentColumn*tailSpacing/(((CGFloat)warpCount-1));
                    make.right.equalTo(tempSuperView).multipliedBy(currentColumn/((CGFloat)warpCount-1)).offset(offset);
                }
            }];
            prev = v;
        }
    }
    
    - (void)mas_distributeSudokuViewsWithFixedLineSpacing:(CGFloat)fixedLineSpacing
                                    fixedInteritemSpacing:(CGFloat)fixedInteritemSpacing
                                                warpCount:(NSInteger)warpCount
                                               topSpacing:(CGFloat)topSpacing
                                            bottomSpacing:(CGFloat)bottomSpacing
                                              leadSpacing:(CGFloat)leadSpacing
                                              tailSpacing:(CGFloat)tailSpacing {
        
        [self mas_distributeSudokuViewsWithFixedItemWidth:0 fixedItemHeight:0 fixedLineSpacing:fixedLineSpacing fixedInteritemSpacing:fixedInteritemSpacing warpCount:warpCount topSpacing:topSpacing bottomSpacing:bottomSpacing leadSpacing:leadSpacing tailSpacing:tailSpacing];
    }
    
    - (NSArray *)mas_distributeSudokuViewsWithFixedItemWidth:(CGFloat)fixedItemWidth
                                             fixedItemHeight:(CGFloat)fixedItemHeight
                                            fixedLineSpacing:(CGFloat)fixedLineSpacing
                                       fixedInteritemSpacing:(CGFloat)fixedInteritemSpacing
                                                   warpCount:(NSInteger)warpCount
                                                  topSpacing:(CGFloat)topSpacing
                                               bottomSpacing:(CGFloat)bottomSpacing
                                                 leadSpacing:(CGFloat)leadSpacing
                                                 tailSpacing:(CGFloat)tailSpacing {
        if (self.count < 1) {
            return self.copy;
        }
        if (warpCount < 1) {
            NSAssert(false, @"warp count need to bigger than zero");
            return self.copy;
        }
        
        MAS_VIEW *tempSuperView = [self star_commonSuperviewOfViews];
        
        NSArray *tempViews = self.copy;
        if (warpCount > self.count) {
            for (int i = 0; i < warpCount - self.count; i++) {
                MAS_VIEW *tempView = [[MAS_VIEW alloc] init];
                [tempSuperView addSubview:tempView];
                tempViews = [tempViews arrayByAddingObject:tempView];
            }
        }
        
        NSInteger columnCount = warpCount;
        NSInteger rowCount = tempViews.count % columnCount == 0 ? tempViews.count / columnCount : tempViews.count / columnCount + 1;
        
        MAS_VIEW *prev;
        for (int i = 0; i < tempViews.count; i++) {
            
            MAS_VIEW *v = tempViews[i];
            NSInteger currentRow = i / columnCount;
            NSInteger currentColumn = i % columnCount;
            
            [v mas_makeConstraints:^(MASConstraintMaker *make) {
                if (prev) {
                    // 固定宽度
                    make.width.equalTo(prev);
                    make.height.equalTo(prev);
                }
                else {
                    // 如果写的item高宽分别是0,则表示自适应
                    if (fixedItemWidth) {
                        make.width.equalTo(@(fixedItemWidth));
                    }
                    if (fixedItemHeight) {
                        make.height.equalTo(@(fixedItemHeight));
                    }
                }
                
                // 第一行
                if (currentRow == 0) {
                    make.top.equalTo(tempSuperView).offset(topSpacing);
                }
                // 最后一行
                if (currentRow == rowCount - 1) {
                    // 如果只有一行
                    if (currentRow != 0 && i-columnCount >= 0) {
                        make.top.equalTo(((MAS_VIEW *)tempViews[i-columnCount]).mas_bottom).offset(fixedLineSpacing);
                    }
                    make.bottom.equalTo(tempSuperView).offset(-bottomSpacing);
                }
                // 中间的若干行
                if (currentRow != 0 && currentRow != rowCount - 1) {
                    make.top.equalTo(((MAS_VIEW *)tempViews[i-columnCount]).mas_bottom).offset(fixedLineSpacing);
                }
                
                // 第一列
                if (currentColumn == 0) {
                    make.left.equalTo(tempSuperView).offset(leadSpacing);
                }
                // 最后一列
                if (currentColumn == columnCount - 1) {
                    // 如果只有一列
                    if (currentColumn != 0) {
                        make.left.equalTo(prev.mas_right).offset(fixedInteritemSpacing);
                    }
                    make.right.equalTo(tempSuperView).offset(-tailSpacing);
                }
                // 中间若干列
                if (currentColumn != 0 && currentColumn != warpCount - 1) {
                    make.left.equalTo(prev.mas_right).offset(fixedInteritemSpacing);
                }
            }];
            prev = v;
        }
        return tempViews;
    }
    @end
    

    相关文章

      网友评论

      • QL_fish:可以发下GitHub链接吗?
        鬼丶白:@QL_fish 客气
        QL_fish:@soime 多谢:smile:
        鬼丶白:https://github.com/JLLJHD/Masnory-
      • 爱恨的潮汐:我怎么找不到这两个方法
        爱恨的潮汐:@soime 我昨天在gitHub找到你的demo了,还给你添加一种布局。我发现你有一个布局,宽度传了还是无效。我做了下修改。
        鬼丶白:已更新 方法
        鬼丶白:@爱恨的潮汐 稍等我更新一下

      本文标题:iOS Masonry实现九宫格布局

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