当同事问到我这个问题时,我脑子中直接冒出了一个词“弹性盒子”。

问题:

有一个 Cell 中有 4 个并排排列的控件,布局如下图所示:

假设:

1、        这些控件高度和y坐标固定。

2、        蓝色控件x位置固定,但右端对齐于黑色控件。

3、        黑色、红色、绿色控件宽度固定,右端对齐于右侧的控件(绿色控件右对齐于cell 的右边)。

要求:

1、        当黑色、红色、绿色控件中的任意一个控件隐藏时,其余两个控件自动右移占据隐藏控件的控件,蓝色控件则自动布满剩下的宽度。以下是分别隐藏其中一个控件的效果:

2、        依次类推,当隐藏其中任意2个控件和3个控件全都隐藏的效果如下图所示:

如果是 HTML5,这个问题用“弹性盒子”来解决是再合适不过了。但是“弹性盒子”是 CSS 3.0中新增的内容,iOS 并不支持弹性盒子,我们只能自己来解决这个问题。

幸好 iOS 有自动布局,我们可以用自动布局来解决这个问题(当然还需要一点点代码)。

一、     UI 设计

打开故事板,向viewcontrollerz中拖入4个UIView,和3个按钮,如下图所示:

这个4个 UIView 和 3个 UIButton 分别是干什么的,相信你已经能一目了然了。按钮先不管,先看看4个View。

蓝色view的自动布局约束是这样的:

top:24,leading:16,height:24,trailing:10

黑色、红色、绿色 view 的布局约束都是一样的:

width:37,height:24,top:24,trailing:10

四个UIView 分别连接至如下 IBOutlet:

蓝色  v1

黑色  v2

红色  v3

绿色  v4

三个按钮的点击事件则分别连接到三个IBAction:

@IBActionfunc hideGray(sender: AnyObject) {

hide(v2)

}

@IBAction func hideRed(sender: AnyObject) {

hide(v3)

}

@IBAction func hideGreen(sender: AnyObject) {

hide(v4)

}

hide()方法待会介绍。

一、     弹性盒子设计

当黑色、红色、绿色view隐藏时(即hidden 属性为true),自动释放其占据的空间,我们需要让它们的布局约束根据hidden属性进行改变。

从上面我们可以得知,它们的自动布局约束主要是如下几个:

width、height、leading、trailing。

这几个布局跟View所占据的空间有密切关系。其中,height我们不用管,因为它们当width=0 时它们的占据的空间就已经释放了,height值是多少就无关紧要了。

那么也就是说,当view隐藏时,我们让view的width、leading、trailing同时为0,就释放了view所占据的空间。

因此,我们需要在运行时获取width、leading、trailing这三个约束,并根据hidden属性修改它们。那么我们能够在运行时获得View的指定约束吗?答案是肯定的。

我们知道,UIView有一个 constraints()方法,返回一个NSLayoutConstraints数组,包含了其所有的width、height是属于view的constrains,而leading、trailing则是属于superview的。我们可以通过遍历这两个数组来找到我们想要的约束。

我们用一个UIView的扩展来实现这个目的:

extension UIView{

func widthConstraint()->NSLayoutConstraint?{

for constraint in self.constraints() {

let firstItem = constraint.firstItem as? UIView

if firstItem == self && constraint.firstAttribute ==NSLayoutAttribute.Width{

println("I gotit:\(constraint)")

return constraint as?NSLayoutConstraint

}

}

return nil

}

func leadingConstraint()->NSLayoutConstraint?{

if self.superview == nil {

return nil

}

for constraint in self.superview!.constraints() {// 这个约束是在superview 中了

let firstItem = constraint.firstItem as? UIView

let secondItem = constraint.secondItem as? UIView

if firstItem == self && constraint.firstAttribute ==NSLayoutAttribute.Leading{

println("I gotit:\(constraint)")

return constraint as?NSLayoutConstraint

}

}

return nil

}

func trailingConstraint()->NSLayoutConstraint?{

if self.superview == nil {

return nil

}

for constraint in self.superview!.constraints() {// 这个约束是在superview 中了

let firstItem = constraint.firstItem as? UIView

if firstItem == self && constraint.firstAttribute ==NSLayoutAttribute.Trailing{

println("I gotit:\(constraint)")

return constraint as?NSLayoutConstraint

}

}

return nil

}

}

然后我们来设计一个弹性盒子,用来管理这三个View。弹性盒子类的主要目的,是将这些View的三个约束的值保存到一个地方(比如说字典中),然后当某个View的hidden属性设为false时,将约束恢复至原来的值并显示出来。

class FlexibleBox:NSObject{

structViewSpace:Printable{

var widthConstant:CGFloat = 0

var leadConstant:CGFloat = 0

var trailConstant:CGFloat = 0

var description: String {

return "width-\(widthConstant)\nleading -

\(leadConstant)\ntrailing- \(trailConstant)"

}

}

var cachedConstraints = [UIView:ViewSpace]()

func addViews(views:[UIView]){

for view in views {

addView(view)

}

}

func addView(v:UIView){

var space = ViewSpace()

if let constraint = v.trailingConstraint() {

space.trailConstant = constraint.constant

}

if let constraint = v.leadingConstraint() {

space.leadConstant = constraint.constant

}

if let constraint = v.widthConstraint() {

space.widthConstant = constraint.constant

}

cachedConstraints[v]=space

println("\(space)")

}

func freeViewSpace(v:UIView){

v.widthConstraint()?.constant = 0

v.leadingConstraint()?.constant = 0

v.trailingConstraint()?.constant = 0

}

func resumeViewSpace(v:UIView){

let space = cachedConstraints[v] ?? ViewSpace()

v.trailingConstraint()?.constant = space.trailConstant

v.leadingConstraint()?.constant = space.leadConstant

v.widthConstraint()?.constant = space.widthConstant

}

deinit{

cachedConstraints.removeAll(keepCapacity: false)

}

}

二、     使用弹性盒子

在View Controller 中声明一个弹性盒子:

let flexBox = FlexibleBox()

然后在viewDidLoad方法中:

flexBox.addViews([v2,v3,v4])

然后但点击按钮时,调用如下方法隐藏(或取消隐藏)一个View:

func toggleViewHiddenStatus(v:UIView){

if v.hidden == false {

flexBox.freeViewSpace(v)

}else{

flexBox.resumeViewSpace(v)

}

v.hidden = !v.hidden

self.view.setNeedsLayout()

}

最后一句self.view.setNeedsLayout()将导致所有自动布局约束被重新计算。

iOS 自动布局和弹性盒子相关推荐

  1. flex属性值----弹性盒子布局

    里面的属性都 是在有display: flex的情况 下才生效. 兼容性写法:   display: -webkit-box; /*老版本语法: Safari, iOS, Android browse ...

  2. html弹性盒子垂直排列,css3弹性盒子布局

    css3弹性盒子布局 CSS3 弹性盒( Flexible Box 或 flexbox),是一种当页面需要适应不同的屏幕大小以及设备类型时确保元素拥有恰当的行为的布局方式. 引入弹性盒布局模型的目的是 ...

  3. flex html 页面移动,HTML页面布局之flex弹性盒子

    这里是修真院前端小课堂,本篇分析的主题是 [HTML页面布局之flex弹性盒子] 每篇分享文从 [背景介绍][知识剖析][常见问题][解决方案][编码实战][扩展思考][更多讨论][参考文献] 八个方 ...

  4. css3弹性盒子模型之box-flex

    css3弹性盒子模型之box-flex 浏览器支持 目前没有浏览器支持 box-flex 属性. Firefox 支持替代的 -moz-box-flex 属性. Safari.Opera 以及 Chr ...

  5. 弹性盒子内容体居右对其_CSS怎么实现弹性盒中的元素居中对齐

    css实现元素对齐(居中对齐弹性盒的各项 元素),在我们网页设计中是较为常见的一个功能效果.我们可以通过css中的align-items等相关css属性来实现. 推荐参考:<CSS教程> ...

  6. 弹性盒子 flex-direction

    使用弹性盒子可以更方便的对页面内容进行布局 flex-direction指定了子元素在父元素盒子中的排列方式 1.flex-direction:row flex默认排列方式,从左到右排列,左对齐 2. ...

  7. 11.18-11.19总结(transform,transition,媒体查询,弹性盒子)

    1.变化 transform 属性:偏移 translate    transform:translate(30px,40px);     比原来的位置右移30px,下移40px transform: ...

  8. ul弹性怎么一行显示_css3系列之弹性盒子 flex

    作者:杨耿 https://www.cnblogs.com/yanggeng/p/11212526.html 弹性盒子(伸缩盒) 注意,本篇会很长,非常长, 因为弹性盒子的知识点比较多 搜索 弹性盒子 ...

  9. 0507css3基础:弹性盒子、媒体查询

    |-弹性盒子 |--定义弹性盒子  display:flex |--定义子元素的排列方式  flex-direction |--定义子元素的换行方式  flex-wrap |--定义子元素的对齐方式 ...

最新文章

  1. 2021牛客寒假算法基础集训营1 题解
  2. Xftp使用教程——问答方式
  3. 代码质量 重构 代码鸡汤
  4. mybatis-plus如和获取当天得数据_MybatisPlus多数据源及事务解决思路
  5. ESXi 内存分配原理
  6. 为什么数据科学家需要承担开发运维的工作?
  7. C++STL优先队列使用
  8. python网络图可视化_蜘蛛网图实现Python可视化的方法
  9. 香港十大外汇交易平台排名(2021最新版)
  10. win7桌面仿linux桌面,windows10开启 linux子系统桌面,巨详细,值得一藏-win7桌面主题...
  11. PNAS | 人类线粒体的双亲遗传模式
  12. zblog php 模板修改,ZBlog博客程序zblogPHP主题模板定制仿制修改
  13. 色彩管理实验 matlab,对色彩管理的一些认识和运用
  14. C语言-简单的Simon游戏
  15. VMware Workstation中部署VMware vSphere 7.0
  16. Re:从零开始的DS生活 轻松和面试官扯一个小时栈
  17. mac修改终端字体样式和大小
  18. Windows平台下的内存泄漏检测
  19. BIMe+IOT+5G深度融合的智慧管理平台
  20. WinXPsp3安装IIS6报错

热门文章

  1. C++ 使用new申请内存
  2. 通知计算机大赛的英语作文,关于诗歌比赛(通知)的英语作文
  3. Windows系统安装SSH服务(OpenSSH服务)、pscp服务、putty服务
  4. 基于西门子S7-1500的大型焊接机全套程序,使用博图V14打开(带全部注释,需要源程序的可以加微信x241602)...
  5. 计算机网络 华南理工大学期末重点 第四章 网络层 谢希仁
  6. CRM助力医药行业通路建设
  7. 阿里云国际版邮件服务套餐购买流程
  8. win7运行在哪_控制面板在哪,n卡控制面板打不开
  9. 机器学习入门(二)--CASIA-HWDB(tensorflow)微调efficientNetB0实现手写字体的识别
  10. mongoDB数据建模