您好、欢迎来到现金彩票网!
当前位置:21点 > 自动布局 >

先进的自动布局工具箱

发布时间:2019-06-10 13:44 来源:未知 编辑:admin

  在我的上一个项目中,因为是面向公司内部使用的客户端,所以我直接抛弃了iOS5,在项目中大量使用了iOS6中的新特性:自动布局,才发现生活可以如此美好(除了调bug的时候),发张图大家感受一下,下面分别为横屏和竖屏下的布局,再也不要像之前那样适配的死去活来了:horizontalvertical

  这篇文章并没有具体介绍自动布局的一些基本概念,主要讲解了一些高级的使用方法和调试技巧,文中有的句子比较长,意思也有点难懂,所以需要静下心仔细揣摩。如果你刚接触自动布局,推荐你先看这几篇文章:1.官方的Guide:Beginning Auto Layout in iOS 6: Part 2/2WWDC 2012 Session笔记202, 228, 232 AutoLayout(自动布局)入门##############################以下是正文###########################自动布局在OS X10.7中被引进,一年后在iOS 6中也可以用了。不久在iOS 7中的程序将会有望设置全局字体大小,因此,几乎在不同屏幕大小和方向上,用户界面布局需要更大的灵活性。Apple也在自动布局上花了很大功夫,所以如果你还没做过这一块,现在就是接触这个技术的好时机。很多开发者在第一次尝试使用时都非常挣扎,因为用Xcode 4的Interface Builder建立基于布局约束的体验非常糟糕。但不要因为这个灰心。自动布局其实比现在Interface Builder所支持的要好。Xcode 5在这块中将会带来重要的变化。这篇文章不是用来介绍Auto Layout的。如果你还没用过它,那还是先去WWDC 2012看看基础教程吧(1,2,3)。反而我们会专注于一些高级的技巧和方法,这将会让你使用自动布局的时候效率更高,生活更幸福。大多数内容在WWDC会议中都有提到,但是他们都是在日常工作中容易被监督或遗忘的。首先我们总结一下自动布局将视图显示到屏幕上的步骤。当你根据自动布局尽力写出你想要的布局种类时,特别是高级的使用情况和动画,这有利于后退一步,并回忆布局过程是怎么工作的。和springs,struts比起来,在视图被显示之前,自动布局引入了两个额外的步骤:更新约束和布局视图。每一步都是基于前一步操作的;显示基于布局视图,布局视图基于更新约束。第一步:更新约束,可以被认为是一个“计量传递”。这发生于自下而上(从子视图到父视图),并准备设置视图frame所需要的布局信息。你可以通过调用setNeedsUpdateConstraints来触发这个传递,同时,你对约束条件系统做出的任何改变都将自动触发这个方法。无论如何,通知自动布局关于自定义视图中任何可能影响布局的改变是非常有用的。谈到自定义视图,你可以在这个阶段重写updateConstraints来为你的视图增加需要的本地约束。第二步:布局,发生于自上而下(从父视图到子视图)。这种布局传递实际上是通过设置frame(在OS X中)或者center和bounds(在iOS中)将约束条件系统的解决方案应用到视图上。你可以通过调用setNeedsLayout来触发这个传递,这并不会立刻应用布局,而是注意你稍后的请求。因为所有的布局请求将会被合并到一个布局传递,所以你不需要为经常调用这个方法而困扰。你可以调用layoutIfNeeded/layoutSubtreeIfNeeded(iOS/OS X)来强制系统立即更新视图树的布局。如果你下一步操作依赖于更新后视图的frame,这将非常有用。在你自定义的视图中,你可以重写layoutSubviews/layout来获得控制布局变化的所有权。我们稍后将展示使用方法。最终,不管你是否用了自动布局,显示器都会将自上而下将渲染视图传递到屏幕上,你也可以通过调用setNeedsDisplay来触发,这将会导致所有的调用都被合并到一起推迟重绘。重写熟悉的drawRect:能够让我们获得自定视图中显示过程的所有权。 既然每一步都是基于前一步操作的,如果有任何布局改变没有被解决,那么,显示传递将会触发一个布局传递。相同的,如果约束条件系统有没有更新的改变,布局变化也将会触发更新约束条件。需要牢记的是,这三步并不是单向的。基于约束条件的布局是一个迭代的过程,布局传递可以基于前一个布局方案做出更改,这将再次接着另一个布局传递后触发更新约束条件。这可以被用来创建高级的自定义视图布局,但是如果你每一次调用自定义layoutSubviews都会导致另一个布局传递,那么你将会陷入一个无限循环中。当创建一个自定义视图时,你需要知道关于自动布局的这些事情:具体指定一个合适的固有内容大小,区分开视图的frame和alignment rect,激活baseline-aligned布局,如何hook into到布局过程。我们将会逐一了解这些部分。固有内容大小是一个视图期望为其显示特定内容得到的大小。比如,UILabel有一个基于字体的首选高度,一个基于字体和显示文本的首选宽度。一个UIProgressView仅有一个基于其插图的首选高度,但没有首选宽度。一个没有格式的UIView既没有首选宽度也没有首选高度。如果你自定义的视图有一个固有内容大小,你必须决定,根据内容来显示,而且你需要指定这个大小。为了在自定义视图中实现固有内容大小,你需要做两件事:重写 intrinsicContentSize为内容返回恰当的大小,无论何时有任何会影响固有内容大小的改变发生时,调用invalidateIntrinsicContentSize。如果这个视图只有一个方向的尺寸设置了固有大小,那么为另一个方向的尺寸返回UIViewNoIntrinsicMetric/NSViewNoIntrinsicMetric。 需要注意的是,固有内容大小必须是独立于视图frame的。例如,不可能返回一个基于frame特定高宽比的固有内容大小。Compression Resistance and Content Hugging(我理解为压缩阻力和内容吸附性,实在是想不到更贴切的名称了,压缩阻力是控制视图在两个方向上的收缩性,内容吸附性是当视图的大小改变时,它会尽量让视图靠近它的固有内容大小)每个视图在两个方向上都分配有内容压缩阻力优先级和内容吸附性优先级。只有当视图定义了固有内容大小时这些属性才能起作用,如果没有定义内容大小,那就没发阻止被压缩或者吸附了。在后台中,固有内容大小和这些优先值被转换为约束条件。一个固有内容大小为{100,30}的label,水平/垂直压缩阻力优先值为750,水平/垂直的内容吸附性优先值为250,这四个约束条件将会生成:如果你不熟悉上面约束条件所使用的可视格式语言,你可以到Apple文档中了解。记住,这些额外的约束条件对了解自动布局的行为带来了隐含的帮助,同时也更好的理解它的错误信息。自动布局并不会操作视图的frame,但能作用于视图的alignment rect。大家很容易忘记细微的差别,因为在很多情况下,他们是相同的。但是alignment rect实际上是一个强大的新概念:从一个视图可视外观分离出布局对齐边缘。比如,一个自定义icon类型的按钮比我们期望点击目标还要小的时候,这将会很难布局。当插图显示在一个更大的frame中时,我们将不得不了解它显示的大小,并且调整相应按钮的frame,这样icon才会和其他界面元素排列好。当我们想要在内容的周围绘制像badges,阴影,倒影的装饰时,也会发生同样的情况。我们可以使用alignment rect简单的定义需要用来布局的矩形。在大多数情况下,你仅需要重写alignmentRectInsets方法,这个方法允许你返回相对于frame的edge insets。如果你需要更多控制权,你可以重写alignmentRectForFrame:和frameForAlignmentRect:。如果你不想减去固定的insets,而是计算基于当前frame的alignment rect,那么这两个方法将会非常有用。但是你需要确保这两个方法是互为可逆的。在这种情况下,回忆上面提及到的视图固有内容大小引用它的alignment rect,而不是frame。这是有道理的,因为自动布局直接根据固有内容大小产生压缩阻力和内容吸附约束条件。为了使约束条件能够使用NSLayoutAttributeBaseline属性对自定义视图奏效,我们需要做一些额外的工作。当然,只有我们讨论的自定义视图中有类似baseline的东西时,才起作用。在iOS中,可以通过实现viewForBaselineLayout来激活baseline alignment。在这里返回的视图底边缘将会作为baseline。默认实现只是简单的返回自己,然而自定义的实现可以返回任何子视图。在OS X中,你不需要返回一个子视图,而是重新定义baselineOffsetFromBottom返回一个从视图底部边缘开始的offset,这和在iOS中一样,默认实现都是返回0.在自定义视图中,你能完全控制它子视图的布局。你可以增加本地约束,如果内容变化需要,你可以改变本地约束,你可以为子视图调整布局传递的结果,或者你可以选择完全自动布局。尽管你明智的使用这个权利。大多数情况下可以通过为你的子视图简单的增加本地约束来处理。如果我们想用几个子视图组成一个自定义视图,我们需要以某种方式布局这些子视图。在自动布局的环境中,自然会想到为这些视图增加本地约束。然而,需要注意的是,这将会使你自定义的视图是基于自动布局的,这个视图不能再被使用于未启用自动布局的windows中。最好通过实现requiresConstraintBasedLayout返回YES明确这个依赖。添加本地约束的地方是updateConstraints。确保在你的实现中调用[super updateConstraints],然后增加任何你需要布局子视图的约束条件。在这个方法中,你不会被允许作废任何约束条件,因为你已经进入以上布局过程所描述的第一步。如果尝试着这样做,将会产生一个友好的错误信息 “programming error”。一个约束条件作废后如果发生了改变,你需要立刻移除这个约束并调用setNeedsUpdateConstraints。事实上,仅在这种情况下你需要触发更新约束条件传递。如果你不能利用布局约束条件达到子视图预期的布局,你可以增加一步,在iOS里重写layoutSubviews或者在OS X里面重写layout。通过这种方式,当约束条件系统得到解决并且结果被应用到视图中,你便已经进入到布局过程的第二步。最极端的情况是不调用父类的实现,自己重写layoutSubviews/layout。这就意味着你为这个视图里的视图树选择了自动布局。从现在起,你可以按喜欢的方式手动放置子视图。如果你仍然想使用约束条件布局子视图,你需要调用[super layoutSubviews]/[super layout],然后对布局进行微调。你可以通过这种方式创建布局,但这却不能定义使用约束条件,比如,布局涉及到视图大小和视图之间间距的关系。另一个有趣的使用案例就是创建一个布局依赖的视图树。当自动布局完成第一次传递并且为自定义视图的子视图设置好frame后,你便可以检查子视图的位置和大小,并为视图层级和(或)约束条件做出调整。WWDC session 228 Best Practices for Mastering Auto Layout有一个很好的例子。 你也可以在第一次布局传递完成后再决定改变约束条件。比如,如果视图变得太窄,将排成一行的子视图转变成两行。

http://mervynsons.com/zidongbuju/2.html
锟斤拷锟斤拷锟斤拷QQ微锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷微锟斤拷
关于我们|联系我们|版权声明|网站地图|
Copyright © 2002-2019 现金彩票 版权所有