MasonryFloatLayout : 基于Masonry的浮动布局


前言


在iOS中使用Masonry进行布局算是日常操作,但是类似于网页的浮动布局的时候,具体示意图如下.

移除其中的某个元素,剩下的元素就会往某个方向进行移动,在Web端,这种布局方式就叫做浮动布局.

另外还有下面的这种情况,虽然也进行浮动但是仍然还另外一边保持着约束关系,这一种在iOS也是比较常见的约束情况.

在iOS的Masonry使用实现上述过程其实非常麻烦的,如果是我们基于Masonry,基于这种情况,我们一般会有两种写法,一种是状态穷举法,另外一种是临时视图变量记录法.

状态穷举法例:

状态穷举法就是所有的视图组合情况列举出来然后添加对应的约束布局.具体示例可以看下面代码.

- (void)loseConstraintsAction {
    if (!_A.hidden && !_B.hidden && !_C.hidden) {
        [_A mas_remakeConstraints:^(MASConstraintMaker *make) {
            make.left.equalTo(self.view).offset(20.0f);
        }];
        [_B mas_remakeConstraints:^(MASConstraintMaker *make) {
            make.left.equalTo(self.A.mas_right).offset(8.0f);
        }];
        [_C mas_remakeConstraints:^(MASConstraintMaker *make) {
            make.left.equalTo(self.B.mas_right).offset(8.0f);
        }];
    }
    
    if (!_A.hidden && _B.hidden && !_C.hidden) {
        [_A mas_remakeConstraints:^(MASConstraintMaker *make) {
            make.left.equalTo(self.view).offset(20.0f);
        }];
        [_C mas_remakeConstraints:^(MASConstraintMaker *make) {
            make.left.equalTo(self.A.mas_right).offset(8.0f);
        }];
    }
    if (_A.hidden && _B.hidden && !_C.hidden) {
        [_C mas_remakeConstraints:^(MASConstraintMaker *make) {
            make.left.equalTo(self.view).offset(8.0f);
        }];
    }
}

状态穷举法算是非常暴力的方案了.状态穷举法的写法形式多种多样,但是整体思想是一致的, 穷举法虽然理解起来简单, 但是弊端也是显而易见的,代码量却是不容小觑,每增加一种组合,我们就需要多一种约束方案.....


临时视图变量记录法:

临时变量记录法就是使用一个临时变量记录与哪个视图建立约束,具体的代码示例如下所示.

- (void)loseConstraintsAction {
    UIView *lastView = self.view;
    if (!_A.hidden) {
        [_A mas_remakeConstraints:^(MASConstraintMaker *make) {
            make.left.equalTo([lastView isEqual:self.view] ? lastView : lastView.mas_right).offset(20.0f);
        }];
        lastView = _A;
    }
    if (!_B.hidden) {
        [_B mas_remakeConstraints:^(MASConstraintMaker *make) {
            make.left.equalTo([lastView isEqual:self.view] ? lastView : lastView.mas_right).offset(8.0f);
        }];
        lastView = _B;
    }
    if (!_C.hidden) {
        [_C mas_remakeConstraints:^(MASConstraintMaker *make) {
            make.left.equalTo([lastView isEqual:self.view] ? lastView : lastView.mas_right).offset(8.0f);
        }];
    }
}

相比于穷举法,在代码结构上已经有很大的改观,但是整体代码仍然让人感觉不是那么满意.

由此骚栋就在想是否可以基于Masonry封装一个库,来实现这种浮动效果呢? 所以我就封装了一个基于Masonry的浮动布局 MasonryFloatLayout.

在说实现之前,我们先看一下如何使用封装好的 MasonryFloatLayout.


MasonryFloatLayout的使用


  • 首先先导入Demo中 MasonryFloatLayout 文件夹,如下图所示.
image
  • 这里需要改动的就是 UIViewFloatLayoutHeader 的Masonry的文件路径地址,如果报错,请导入正确的文件路径地址.
#ifndef UIViewFloatLayoutHeader_h
#define UIViewFloatLayoutHeader_h

#import "Masonry/Masonry.h"

#endif /* UIViewFloatLayoutHeader_h */
  • 在需要的ViewController或者View中引入头文件.
#import "NSArray+FloatLayout.h"
  • 假设我们现在有三个View,需要进行浮动布局,那么我们先要把初始化工作完成.包括声明View属性和懒加载View方法实现,当然了,你可以按照你的习惯来.
@property (nonatomic, strong) UIView *firstView;
@property (nonatomic, strong) UIView *secondView;
@property (nonatomic, strong) UILabel *thirdView;
- (UIView *)firstView {
    if (_firstView == nil) {
        _firstView = [[UIView alloc] initWithFrame:CGRectZero];
        _firstView.backgroundColor = [UIColor redColor];
    }
    return _firstView;
}

- (UIView *)secondView {
    if (_secondView == nil) {
        _secondView = [[UIView alloc] initWithFrame:CGRectZero];
        _secondView.backgroundColor = [UIColor orangeColor];
    }
    return _secondView;
}

- (UILabel *)thirdView {
    if (_thirdView == nil) {
        _thirdView = [[UILabel alloc] initWithFrame:CGRectZero];
        _thirdView.backgroundColor = [UIColor blueColor];
        _thirdView.textColor = [UIColor whiteColor];
        _thirdView.text = @"333333333333";
    }
    return _thirdView;
}
  • 接下来我们需要浮动约束布局的添加了.和Masonry布局一样,首先我们需要使用mas_remakeFloatLayoutConstraints给每一个View添加具体的布局.最后再用数组添加浮动布局.具体代码如下所示.
    [self.firstView mas_remakeFloatLayoutConstraints:^(MASConstraintMaker * _Nonnull make, UIView * _Nonnull lastView, UIView * _Nonnull nextView) {
        make.left.equalTo(@50);
        make.height.equalTo(@100);
        make.width.equalTo(@100);
        make.lastFloatConstraint.offset(10.0f);
        make.nextFloatConstraint.offset(-10.0f).priorityHigh();
    }];
    [self.secondView mas_remakeFloatLayoutConstraints:^(MASConstraintMaker * _Nonnull make, UIView * _Nonnull lastView, UIView * _Nonnull nextView) {
        make.left.equalTo(@50);
        make.height.equalTo(@100);
        make.width.equalTo(@100);
        make.lastFloatConstraint.offset(30.0f).priorityLow();
        make.nextFloatConstraint.offset(-10.0f);
    }];
    [self.thirdView mas_remakeFloatLayoutConstraints:^(MASConstraintMaker * _Nonnull make, UIView * _Nonnull lastView, UIView * _Nonnull nextView) {
        make.left.equalTo(@50);
        make.height.equalTo(@100);
        make.lastFloatConstraint.offset(10.0f);
        make.nextFloatConstraint.offset(-10.0f);
    }];

    [@[self.thirdView, self.firstView, self.secondView] mas_remakeFloatLayoutConstraintsWithOrientation:FloatLayoutOrientationBottomToTop needLastConstraint:need];
  • 在上面添加约束过程中,我们需要使用 lastFloatConstraintnextFloatConstraint,这两个属性都是来源于 MASConstraintMaker+FloatLayout,我们可以通过这两个属性添加与上一个View和下一个View的间距关系.
@property (nonatomic, strong) MASFloatLayoutConstraint *lastFloatConstraint;

@property (nonatomic, strong) MASFloatLayoutConstraint *nextFloatConstraint;
  • 当然了,间距关系也可以设置优先级,这样的话.如果有间距约束冲突,通过设置优先级来解决这种问题.这在上面的示例中也是有所体现.
- (MASFloatLayoutConstraint * (^)(MASLayoutPriority priority))priority;

- (MASFloatLayoutConstraint * (^)(void))priorityLow;

- (MASFloatLayoutConstraint * (^)(void))priorityMedium;

- (MASFloatLayoutConstraint * (^)(void))priorityHigh;
  • mas_remakeFloatLayoutConstraints 方法的Block参数除了常见的MASConstraintMaker *make 之外,还会返回上一个视图lastView和下一个视图nextView,当然了,这两个参数有可能是nil.
typedef void(^FloatConstraintMaker)(MASConstraintMaker *make, UIView *lastView, UIView *nextView);
  • 每一个视图的约束添加完成之后,我们添加浮动布局,浮动布局是基于NSArray的分类 NSArray+FloatLayout, mas_remakeFloatLayoutConstraintsWithOrientation 方法总共有两个参数.一个是用来设定浮动的方向,另外一个是用来设定最后一个视图与父视图的关系,类似于上一个模块说到的第二种情况.
typedef enum : NSUInteger {
    FloatLayoutOrientationUnknow,      // 未知或者根据自定义的约束进行约束布局
    FloatLayoutOrientationLeftToRight, // 从左到右进行布局
    FloatLayoutOrientationRightToLeft, // 从右到左进行布局
    FloatLayoutOrientationTopToBottom, // 从上到下进行布局
    FloatLayoutOrientationBottomToTop, // 从下到上进行布局
} FloatLayoutOrientation;

/// 执行浮动布局
/// @param orientation 相对于父视图的浮动方向
/// @param needLastConstraint 是否需要添加最后的约束
- (void)mas_remakeFloatLayoutConstraintsWithOrientation:(FloatLayoutOrientation)orientation
                                     needLastConstraint:(BOOL)needLastConstraint;

整体的使用流程就是这样的.整体来说和原来的Masonry布局代码方式没有什么太大区别.具体的示例可以看一下我的Demo.


总结


如果在使用过程中遇到任何问题欢迎随时找我,骚栋在这里谢谢大家了.

MasonryFloatLayout传送门


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345