博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
有趣的Autolayout示例-Masonry实现
阅读量:2192 次
发布时间:2019-05-02

本文共 6494 字,大约阅读时间需要 21 分钟。

文章转自:

有趣的Autolayout示例-Masonry实现

前言

好久没有写Blog了,这段时间有点忙啊=。=

本文举了3个比较有“特点”的Autolayout例子,源于微博上好友的提问,感觉比较有意思,也比较有代表性,就写了出来,分享给大家~
至于为什么用Masonry,那是因为它好用啊!(被问到过有关Masonry的问题,就索性用它来实现吧=。=)。

效果图

image

Github地址

关于例子工程结构

实现的时候采用的是用StoryBoard拖拽约束+Masonry手写代码相结合的方式实现。最关键的地方是用Masonry,为了更好地突出重点。其它的无关紧要的空间约束,直接就拖拽了。

关于Autolayout

刚开始学习Autolayout的时候,什么“Leading Edges”、“Horizontal Centers”,好多啊,感觉一下子适应不来,有时候面对一个界面布局上的需求,可能都无从下手。

总的来说,我觉得Autolayout的关键就是“Constraint(约束)”。其实就是一下两点:

  1. 从显式设置frame的属性,到利用约束控制View的大小、位置。
  2. 思考如何布局时,重点从单个的View,到整体所有View之间的相互关系。

既然没有了具体设置View的frame属性,也就是说,系统会在运行时,通过我们设定的“约束”,计算出每个View的frame,再去绘制屏幕内容。

也就是说,我们设置的Constraint,要能体现出View的位置(x、y坐标)大小(宽高)。无论是用IB拖拽约束,还是手写代码,只要从这个角度去思考,很多问题就都能解决。

有关Autolayout的知识,网上有很多,在这里就不详细列出了,但是有个公式倒是可以贴出来:

1
viewA-attribute = viewB-attribute * multiplier + constant

关于Masonry

好用!

Case 1: 并排两个label,宽度由内容决定。父级View宽度不够时,优先显示左边label的内容

遇到这种跟内容压缩、优先级有关的布局,就不得不提Autolayout中的两个重要的属性“Content Compression Resistance”和“Content Hugging”。

Content Compression Resistance = 不许挤我!

对,这个属性说白了就是“不许挤我”=。=

这个属性的优先级(Priority)越高,越不“容易”被压缩。也就是说,当整体的空间装不小所有的View的时候,Content Compression Resistance优先级越高的,现实的内容越完整。

Content Hugging = 抱紧!

这个属性的优先级越高,整个View就要越“抱紧”View里面的内容。也就是View的大小不会随着父级View的扩大而扩大。

分析

根据要求,可以将约束分为两个部分:

  1. 整体空间足够时,两个label的宽度由内容决定,也就是说,label的“Content Hugging”优先级很高,而且没有固定的Width属性。
  2. 整体空间不够时,左边的label更不容易被压缩,也就是“Content Compression Resistance”优先级更高。

重点:

  1. label不设置具体的宽度(width)属性,宽度由内容决定。
  2. 显示的优先级由“Content Compression Resistance”属性的高低决定。

约束示例图

image

关键代码

关键的代码如下:(label1是左边的label,label2是右边的)

设置位置

// label1: 位于左上角[_label1 mas_makeConstraints:^(MASConstraintMaker *make) {    make.top.equalTo(_contentView1.mas_top).with.offset(5);    make.left.equalTo(_contentView1.mas_left).with.offset(2);    // 40高度    make.height.equalTo(@40);}];// label2: 位于右上角[_label2 mas_makeConstraints:^(MASConstraintMaker *make) {    //左边贴着label1    make.left.equalTo(_label1.mas_right).with.offset(2);    //上边贴着父view    make.top.equalTo(_contentView1.mas_top).with.offset(5);    //右边的间距保持大于等于padding.right,注意是lessThanOrEqual    make.right.lessThanOrEqualTo(_contentView1.mas_right).with.offset(-2);    //只设置高度40    make.height.equalTo(@40);}];

设置内容约束

//设置label1的content hugging 为1000[_label1 setContentHuggingPriority:UILayoutPriorityRequired                           forAxis:UILayoutConstraintAxisHorizontal];//设置label1的content compression 为1000[_label1 setContentCompressionResistancePriority:UILayoutPriorityRequired                                         forAxis:UILayoutConstraintAxisHorizontal];//设置右边的label2的content hugging 为1000[_label2 setContentHuggingPriority:UILayoutPriorityRequired                           forAxis:UILayoutConstraintAxisHorizontal];//设置右边的label2的content compression 为250[_label2 setContentCompressionResistancePriority:UILayoutPriorityDefaultLow                                         forAxis:UILayoutConstraintAxisHorizontal];

小节

灵活运用“Content Compression Resistance”和“Content Hugging”属性。

Case 2: 四个ImageView整体居中,可以任意显示、隐藏

先看看示例的截图:

image

下面的四个Switch控件分别控制上面对应位置的图片是否显示。

分析

  1. 首先就是整体居中,为了实现这个,最简单的办法就是将四个图片“装进”一个容器View里面,然后让这个容器View在整个页面中居中即可。这样就不用控制每个图片的居中效果了。
  2. 然后就是显示与隐藏。在这里我直接控制图片ImageView的宽度,宽度为0的时候不就“隐藏”了吗。

约束示例图

image

解释

之所以这么设置,主要目的有以下几点:

  1. 尽量减少无效的约束,保证约束不多也不少。
  2. 内部的每个imageView约束其实都只有四个:left、centerY、width和height,这样有个好处,就是可以写个函数,专门为View一次性添加这几个约束,大大减少代码量。
  3. 最右边的imageView还要单独设置跟容器View的右边约束,是为了不用设置容器View的width,保证容器View是刚好包含内部的View的,这样整体才是居中的。

关键代码

先看看设置每个imageView约束的函数:

/***  设置view的宽高、左边约束,垂直中心约束**  @param view    要设置的view*  @param size    CGSize*  @param left    左边对齐的约束*  @param centerY 垂直中心对齐的约束**  @return 返回宽约束,用于显示、隐藏单个view*/- (MASConstraint *)setView:(UIView *)view size:(CGSize)size left:(MASViewAttribute *)left centerY:(MASViewAttribute *)centerY {    __block MASConstraint *widthConstraint;    [view mas_makeConstraints:^(MASConstraintMaker *make) {        //宽高固定        widthConstraint = make.width.equalTo(@(size.width));        make.height.equalTo(@(size.height));        //左边约束        make.left.equalTo(left);        //垂直中心对齐        make.centerY.equalTo(centerY);    }];    return widthConstraint;}

接着就是设置容器View的代码:

//containerView 就是 容器View[_containerView mas_makeConstraints:^(MASConstraintMaker *make) {    //只设置高度,宽度由子View决定    make.height.equalTo(@(IMAGE_SIZE));    //水平居中    make.centerX.equalTo(self.view.mas_centerX);    //距离父View顶部200点    make.top.equalTo(self.view.mas_top).offset(200);}];

最后是内部imageView的约束:

//分别设置每个imageView的宽高、左边、垂直中心约束,注意约束的对象//每个View的左边约束和左边的View的右边相等=。=,有点绕口...UIImageView *imageView1 = _imageViews[0];MASConstraint *width = [self setView:imageView1 size:imageViewSize left:_containerView.mas_left centerY:_containerView.mas_centerY];[_widthConstraints addObject:width];UIImageView *imageView2 = _imageViews[1];width = [self setView:imageView2 size:imageViewSize left:imageView1.mas_right centerY:_containerView.mas_centerY];[_widthConstraints addObject:width];UIImageView *imageView3 = _imageViews[2];width = [self setView:imageView3 size:imageViewSize left:imageView2.mas_right centerY:_containerView.mas_centerY];[_widthConstraints addObject:width];UIImageView *imageView4 = _imageViews[3];width = [self setView:imageView4 size:imageViewSize left:imageView3.mas_right centerY:_containerView.mas_centerY];[_widthConstraints addObject:width];//最后设置最右边的imageView的右边与父view的最有对齐[imageView4 mas_makeConstraints:^(MASConstraintMaker *make) {    make.right.equalTo(_containerView.mas_right);}];

控制ImageView显示、隐藏的时候,直接让其宽度等于0就行:

- (IBAction)showOrHideImage:(UISwitch *)sender {    NSUInteger index = (NSUInteger) sender.tag;    MASConstraint *width = _widthConstraints[index];    if (sender.on) {        width.equalTo(@(IMAGE_SIZE));    } else {        width.equalTo(@0);    }}

小节

有时候用个“容器View”管理内部的View,往往会起到事半功倍的效果。而且在组织约束的时候,尽量的将约束统一起来,这样可以用一个函数去设置,减少代码量。

Case 3: 子View的宽度始终是父级View的一半(或者任意百分比)

其实这个很简单=。= 再看看这个公式:

1
viewA-attribute = viewB-attribute * multiplier + constant

这个是Autolayout里面一个约束的不同属性的基本组合关系,替换成宽度的话,就是下面这样:

1
子View的宽度 = 父级View宽度 * 系数 + 常数;

在Masonry里面,其实有个函数“multipliedBy”,就是用来设置multipler属性的(跟原本的NSLayoutConstraint的对应)。

关键代码

如下:

[subView mas_makeConstraints:^(MASConstraintMaker *make) {    //上下左贴边    make.left.equalTo(_containerView.mas_left);    make.top.equalTo(_containerView.mas_top);    make.bottom.equalTo(_containerView.mas_bottom);    //宽度为父view的宽度的一半    make.width.equalTo(_containerView.mas_width).multipliedBy(0.5);}];

接着,只要控制父级View的宽度,子View的宽度就会随着变化了。

小节

multipliedBy在Masonry的Github主页里面没有=。=

所以要养成读头文件的习惯~

总结

有关Autolayout的东西还有好多没有写,什么动画啊、动态修改约束之类的,本文也算是个引子吧,任重而道远~

能看到这的朋友,也算是很有耐心了,哈哈~~

参考

转载地址:http://gbdub.baihongyu.com/

你可能感兴趣的文章
笔试题(一)—— java基础
查看>>
Redis学习笔记(三)—— 使用redis客户端连接windows和linux下的redis并解决无法连接redis的问题
查看>>
Intellij IDEA使用(一)—— 安装Intellij IDEA(ideaIU-2017.2.3)并完成Intellij IDEA的简单配置
查看>>
Intellij IDEA使用(二)—— 在Intellij IDEA中配置JDK(SDK)
查看>>
Intellij IDEA使用(三)——在Intellij IDEA中配置Tomcat服务器
查看>>
Intellij IDEA使用(四)—— 使用Intellij IDEA创建静态的web(HTML)项目
查看>>
Intellij IDEA使用(五)—— Intellij IDEA在使用中的一些其他常用功能或常用配置收集
查看>>
Intellij IDEA使用(六)—— 使用Intellij IDEA创建Java项目并配置jar包
查看>>
Eclipse使用(十)—— 使用Eclipse创建简单的Maven Java项目
查看>>
Eclipse使用(十一)—— 使用Eclipse创建简单的Maven JavaWeb项目
查看>>
Intellij IDEA使用(十三)—— 在Intellij IDEA中配置Maven
查看>>
面试题 —— 关于main方法的十个面试题
查看>>
集成测试(一)—— 使用PHP页面请求Spring项目的Java接口数据
查看>>
使用Maven构建的简单的单模块SSM项目
查看>>
Intellij IDEA使用(十四)—— 在IDEA中创建包(package)的问题
查看>>
FastDFS集群架构配置搭建(转载)
查看>>
HTM+CSS实现立方体图片旋转展示效果
查看>>
FFmpeg 命令操作音视频
查看>>
问题:Opencv(3.1.0/3.4)找不到 /opencv2/gpu/gpu.hpp 问题
查看>>
目的:使用CUDA环境变量CUDA_VISIBLE_DEVICES来限定CUDA程序所能使用的GPU设备
查看>>