Auto Layout 和 Constraints

文章修改
2月1日:添加使用约束编辑约束iOS特性三个部分
2月24日:根据自己的理解,修改iOS特性部分的内容

自动布局Auto Layout

Auto Layout,通过设置在View上的约束,动态计算视图层次结构中所有的View的尺寸和位置。举个栗子,你约束一个Button,令它的水平中心线和一个ImageView相同,并且它的上边缘距离ImageView的下边缘有8个像素。如果ImageView的尺寸或者位置改变,Button会自动调整,以符合之前设置的约束。

基于约束的Auto Layout,使我们搭建能够动态响应内部和外部变化的用户界面。

外部变化

外部变化发生于superview的尺寸或者位置改变,比如,

  • 设备屏幕旋转;

  • 支持不同屏幕大小的设备。

这时,所有的View都要重新计算尺寸和位置。每一次变化,都会刷新视图层级结构的布局。这些变化大部分发生在运行时,它们需要APP能够动态响应。

内部变化

内部变化发生于你的界面中的View的尺寸或者位置发生改变。比如,

  • APP中显示的内容的改变,新的内容可能需要一个新的布局。一般,在显示文字或者图片时会出现这种情况;

  • APP支持动态设置。如果用户可以设置字体大小,这将会改变任何与文本相关的控件的高度或者宽度,布局必须能够适应变化。

约束Constraints

Auto Layout的实现是基于设置在View上的一系列约束的。每一条约束都是一个表达式。

下图是官方文档给的示例图:

苹果官方文档的示例图

这个约束表明,Red View左边缘Blud View右边缘的距离为8。这个等式由以下几个部分组成:

  • Item 1 :表达式中的第一个控件。在这个例子中是Red View

  • Attribute 1 :第一个控件的一个属性。在这个例子中是Red Viewleading edge

  • Relationship :表达式左右两边的关系,可以使等于大于等于或者小于等于。在这个例子中,两边的关系是相等的;

  • Multiplier :和第二个控件的属性相乘的乘数,是一个浮点型。在这个例子中是1.0。一般情况下,这个值不可置为0.0

  • Item 2 :表达式中的第二个控件。在这个例子中是Blue View。它是可以为空的,即表达式变成Item 1 * Attribute 1 = 0.0 * NotAnAttribute + Constant

  • Attribute 2 :第二个控件的一个属性。在这个例子中是Blue Viewtrailing edge

  • Constant :一个浮点型的常数。在这个例子中是8.0

大部分的约束是定义两个控件之间的关系。这些控件必须是View或者是Layout Guide。约束也可以定义一个控件的两个属性之间的关系,比如设置一个控件的上边缘到下边缘的距离、左边缘到右边缘的距离,即它的高度或者宽度。当表达式中的Item 2为空时,它的属性必须被设为Not An Attribute,并且Multiplier置为0.0

约束中用到的属性

通常情况下,包含四个边(leading,trailing,top和bottom),以及高度(height),宽度(width),水平中心点(CenterY),垂直中心点(CenterX)。文本类型的控件还有一个基线(baseline)属性。

image

属性说明

  • Height和Width。这两个属性可以被直接赋值,可以是一个常数,也可以是其他View的Height或者Width值。但是,不可以为负数。

  • Top、Bottom、Baseline。可以和TopBottomBaselineCenterY组合。

  • Leading和Trailing。可以和LeadingTrailingCenterX组合。

  • Left和Right。避免使用这两个属性,而使用LeadingTrailing来替代它们。

  • CenterX和CenterY。CenterX可以和LeadingTrailingLeftRight组合。CenterY可以和TopBottomBaseline组合。

使用属性定义约束

上面提到的属性可以分为两类,尺寸相关位置相关。尺寸相关(如height、width)用来定义物件的大小。位置相关(如leading,top)的属性用来表明该物件和其他物件之间的位置关系。使用这些属性时需要注意:

  • 不要使用尺寸相关的属性去约束一个位置相关的属性。

  • 只可以给尺寸相关的属性直接赋值一个常量。

举几个简单的例子:

// 设置一个固定高度
View.height = 0.0 * NotAnAttribute + 40.0// 设置两个按钮之间的固定距离
Button_2.leading = 1.0 * Button_1.trailing + 8.0// 让两个按钮的左边缘对齐
Button_1.leading = 1.0 * Button_2.leading + 0.0// 给两个按钮相同的宽度
Button_1.width = 1.0 * Button_2.width + 0.0// 让View的中心和父类的中心相同
View.centerX = 1.0 * Superview.centerX + 0.0
View.centerY = 1.0 * Superview.centerY + 0.0// 设置一个View的宽高比
View.height = 2.0 * View.width + 0.0

约束的设置没有最好的,只有最适合的。

约束的优先级

优先级priority是Auto Layout在计算的时候用到的参数。优先级的值可以是1-1000任意整数。系统定义了low(250)、medium(500)、high(750)和required(1000)四个等级。一般情况下,我们手动设置的优先级的值也会集中在这四个等级下。

优先级默认值是1000。

关于Auto Layout是如何通过优先级来计算出解决方案,我在看完官方文档后还是一头雾水。希望有大神可以指点一二。

使用约束

添加约束

在storyboard中有3种方式添加约束。

  • 在View之间使用Control-Drag

  • 使用PinAlign工具;

  • 让Interface Builder自动添加约束。

Control-Dragging

所谓Control-Draging就是按住Control键,用鼠标左键拖动的方式添加约束。这两步操作也可以用按住鼠标右键拖动来替代。

image

当释放鼠标左键后,就会弹出一个HUD,显示可以设置的约束。

image

Interface Builder会根据选择的两个控件以及拖动的方向筛选出可以设置的约束。如果拖动的方向倾向于水平,你可以选择设置水平方向上的间距和垂直方向上的对齐方式。反之,如果拖动的方向倾向与垂直,则可以选择设置垂直方向上的间距和水平方向上的对齐方式。

提示:

  1. 可以从一个控件拖动到另一个控件,设置它们之间的关系。也可以拖动到控件自身,设置宽度和高度;

  2. 不仅可以在Scene中直接拖动,可以在Storyboard左侧的视图大纲中用同样的方式拖动。在大纲中拖动设置约束,会显示出所有的可选约束,而不会进行筛选;

  3. Control-Dragging可以非常快速得设置约束。这些约束是基于Scene中View的当前的位置,因此在设置约束之前要定位好View。

使用Stack、Align、Pin、Resolve工具

Interface Builder在Storyboard的编辑窗口的右下角提供四个自动布局的工具,分别是StackAlignPinResolve Auto Layout Issues

image

当你想精确控制约束的Constant或者想一次性添加多个约束,可以使用Align和Pin工具。使用Align和Pin还有一个好处,我们不是必须要设置好View的位置,而是只需要定好相对位置,添加约束,然后update frames。Auto Layout会自动计算出正确的位置。

Stack Tools

Stack Tools可以将选中的一个或者多个控件嵌入到一个Stack View中,并会重新计算布局。Stack View是iOS 9添加的新特性。

对于Stack View,我还没有弄明白使用方法,所以这里不讲述。

Align Tool

Align Tools可以快速对齐控件。选择一个或多个你想对齐的控件,然后单击Align Tool。然后会弹出可选的一系列对齐方式。

image

选择其中的选项,然后点击Add Constraints。之后,就会自动添加对齐的约束设置。大部分情况下,会选择两个或者两个以上的View来设置对齐。Horizonally in ContainerVertically in Container这两个可以添加到单一的View上。

Pin Tool

Pin是大头针的意思。所以这个工具可以用来给View定位。它可以让我们快速设置一个View相对于它周边View位置或者它的宽高。选择一个你想对其进行定位的View,单击Pin Tool,会弹出如下的窗口。

image

窗口的上半部分,可以设置选中的View的Top,Bottom,Leading,Trailing与相邻最近的View的间距。最初显示的数字是当前的间距。我们可以输入一个自定义的值,还可以点击输入框右边的倒三角,在弹出的下拉菜单中选择参照的View。关于Constrain to margins选项,如果选中,会将父视图的外边距作为间距的值的参考。

image

下半部分可以设置宽高相关的属性。宽和高默认的是Scene中的尺寸,也可以自定义值。宽高比的默认值也是根据Scene中的尺寸进行计算。如果想自定义的话,只有在设置完宽高比之后修改这个约束。

一般情况下,选择一个View,对它进行定位。选择两个及其以上的View设置Equal Height或者Equal Width。使用Pin Tool设置完约束后,可能需要Update frames

Resolve Auto Layout Issues

Resolve Auto Layout Issues提供一些解决Auto Layout问题的方法。上半部分只针对选中的View,下半部分则针对Scene中所有的View。

image

我们可以

  • 根据当前约束更改frame;

  • 根据当前frame更改约束的设置;

  • 添加缺少的约束;

  • 清除已添加的约束;

  • 设置系统推荐的约束。

这些功能字面上写得很清楚,具体的效果大家可以用简单的Demo来看一下。

让Interface Builder为我们设置约束

Interface Builder可以为我们创建部分或者全部的约束。根据所提供的View的尺寸和位置,它会推断出最好的约束。前提是,我们必须确定View的位置并不再更改。一个小小的间距的改变,可能对于整个布局来说确实巨大的。

如果想让Interface Builder来完成约束的添加,单击上文提到的Resolve Auoto Layout Issues工具,点击Reset to Suggested Constraints。Interface Builder就会为已选的(也可以是Scene中全部的)View创建合适的约束。

另外,我们可以自己添加一部分约束,然后选择Add missing Constraints,让Interface Builder来添加剩下的所需的约束。

这种方法可以快速完成约束的设置。但是,有可能运行得到的UI并不是你想要的。要不断地测试UI,修改约束,以达到最终想要的效果。

编辑约束

添加约束之后,需要能够找到它、查看它、编辑它。

在Scene里查看约束

编辑窗口会显示作用于当前选择的View的约束。通过线的形状颜色类型说明当前约束的当前状态。

  • I-bars(两端是T型的线):I-bars显示间距的大小。可能是两个控件之间的大小,可能是一个控件的高度或者宽度。

  • Plain Line(一条普通的直线):Plain Line显示控件边缘的对齐方式。例如,两个或两个以后的控件是左对齐的,那么,这条线会连接着这些控件,并且与它们的Leading之间的间距为0。

  • Solid Line:实线表示这个约束是Required,即priority == 1000。

  • Dash Line:虚线表示这个约束是Optional,即priority < 1000。

  • Red Line:红线表示被约束的影响的控件的约束设置有错误。具体的原因可以点击大纲中每个Scene的右边的箭头查看。这时,箭头是红色的。

  • Orange Line:橘黄色的线表明,Auto Layout根据已有约束计算出来的frame和当前Scene中设置的frame不同。这时,大纲中的右边的箭头是黄色的。可以用Resolve Auot Layout Issues -> Update frames来进行修正位置。

  • Blue Line:蓝色的线表示当前的约束设置是正确的,并且控件的位置和Auto Layout计算出来的位置是一样的。

  • Equal Badges:相等标记表明两个控件的宽度或者高度是相同的。并且标记中包含=符号。

  • Greater-than-or-equal and less-than-or-equal badges:和Equal Badges类似,它们是标记约束的关系是大于等于或者小于等于的,同时也会显示对应的符号。

快速找到并编辑添加的约束

所有添加的约束都陈列在大纲里。这些约束以伪代码的形式呈现。当选择一个约束时,会在Scene中高亮显示,可以帮助我们快速找到它。而且,可以在右侧的Show the Size inspector下对约束的ConstantPriorityMultiplierRelationIdentifierPlaceholder属性进行编辑。

image

一旦UI变得复杂之后,我们用这种方式找约束就会显得很吃力。Show the Size inspector工具可以显示出在当前选中的控件上添加的约束。约束的一部分属性也可以在这里进行修改。

image

注意:这里虽然都是在Show the Size Inspector下进行修改,但是前者是选择一个约束,后者是选择一个控件。

Auto Layout在iOS中的特性

iOS在与Auto Layout方面有一些独有的特性,包括top and bottom layout guidesLayout Margins

Top and Bottom Layout Guides

top and bottom layout guides表示当前的ViewController从最上面到最下面的可见范围。如果不希望显示的内容在UIKit bars(例如status bar,navigation bar,tab bar)下面,那么就可以和上下的layout guide来设置约束。

layout guides是遵守UILayoutSupport协议的。这个协议有一个length属性,来表示guide和root view(root view就是ViewController默认添加的view)边缘的距离:

  • 对于top layout guide,length指明ViewController的root view的上边缘和覆盖在root view上的bar(例如status bar和navigation bar)的底部的距离。

  • 对于bottom layout guide,length指明ViewController的root view的下边缘和覆盖在root view上的bar(例如tab bar)的顶部的距离。

在iOS 9中,guide也可以像控件一样,支持用topbottomheight设置约束。比如,用top layout guide的bottom属性和bottom layout guide的top属性与view设置约束。UILayoutSupport还提供了topAnchorbottomAnchorheightAnchor属性,可以让我们用代码的形式来设置约束。

如果layout guides是view最近的"控件",那么系统会自动将layout guides作为设置约束的对象。当使用Pin Tool时,可以在layout guides和root view的上下边缘进行选择。

Layout margins

Auto Layout为每一个view都定义了margin。margin指的是控件显示内容部分的边缘和控件边缘的距离。就像“回”这个汉字一样,外面的“口”就是控件的外边缘,里面的“口”是控件显示内容的部分的边缘,我暂且称它为内边缘,这两个边缘之间的距离就是margin

可以用layoutMargins或者layoutMarginsGuide属性获得view的margin。layoutMargins允许获取或者设置UIEdgeInsets结构的margin,layoutMarginsGuide则只会获取到只读的UILayoutGuide对象。

每一个view的默认的margin是8。可以根据APP的需要进行修改。__系统给ViewController的root View设置的margin则不能修改__。root View的上下的margin为0,左右的margin为20。

当使用Control-Dragging方式,给一个View和它们父视图设置约束时,默认使用内边缘,而不是外边缘。当使用Pin Tool时,如果Constraint to margins被勾选,则会使用父视图的内边缘作为设置约束的参照,如果没有被勾选,则使用外边缘作为设置约束的参照。所见到的效果就是两种参照下的约束的Constant的值相差一个margin

当在Interface Builder中编辑约束时,First ItemSecond Item的弹出菜单中可以选择Relative to margin。如果勾选,会在topleading等属性后面加上Margin,变成topMarginleadingMargin等,意味着约束的设置参照View的内边缘而不是外边缘。

设置约束时的一些建议

官方文档为我们提供了一些设置约束时的建议

  • __在最相近的两个控件之间创建约束。__假如有3个Button,分别是first,second,third。可以约束first的右边缘和second的左边缘的距离,second的右边缘和third的左边缘的距离。而不要约束first的右边缘和third的左边缘距离,中间隔了一个second。

  • __避免设置固定的高度和宽度。__Auto Layout是动态响应布局的变化。一个控件如果设置固定尺寸,那么就会失去自动调整的能力。

  • update frames时注意,如果这个控件没有设置足够多的约束来确定它的位置和尺寸,那么可能会导致一些意想不到的后果。比如会跑到屏幕外,或者因为宽度、高度为0而消失等等。

  • 给所有的控件取一个有意义的名称。在使用工具时,可以方便地辨别出View。

  • 使用leadingtrailing代替leftright

  • 当使用代码创建约束时,确保将它们的translatesAutoresizingMaskIntoConstraints属性为NO。默认情况下,系统会基于控件的frame自动创建一系列约束。当你添加自己的约束时,不可避免地会和自动生成的约束产生冲突。

参考内容:
苹果官方文档:Auto Layout Guide

本文中的图片均取自苹果官方文档

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/398971.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

tkinter的GUI设计:界面与逻辑分离(三)-- 多页面

知识点&#xff1a; 使用 tkinter.Frame.tkraise() 函数去提升当前 tkinter.Frame 的 z 轴顺序&#xff0c;使得多个 tkinter.Frame 的可见性得以切换 本文基于&#xff1a;win7 python34 1 2 3 4 5 import matplotlib matplotlib.use("TkAgg")from matplotlib.back…

Android源码解析--SwipeMenuListView仿QQ聊天左滑

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请标明出处。 https://blog.csdn.net/lyhhj/article/details/50612714 绪论&#xff1a; 好久没写博客了&#xff0c;最近比较懒&#xff0c;不想写博客&#xff0c;但是在看书&#xff0c;看一些Android进阶的书&#…

java main方法背后的故事?(转)

jvm java 看似一种语言&#xff0c;实则一个巨大的体系的王国&#xff0c;开发这么多年了&#xff0c;还是没有搞懂,我以为我懂了&#xff0c;可是过了一段时间又忘了&#xff0c;所以说还是没懂 1、main方法说起 编译完我们的java文件后&#xff0c;需要有个一含有main方法的类…

亲历腾讯WEB前端开发三轮面试经历及面试题

【一面】~110分钟 2014/09/24 11:20 星期三 进门静坐30分钟做题。 填空题大题问答题 >>填空题何时接触电脑 何时接触前端运算符 字符串处理 延时 display position XMLHttpRequest 正则Jquery绑定事件 cookie >>大题BOM浏览器…

linux网卡名称乱编,小斗CentOS7.x网卡名称错乱、及网卡启动失败。

本帖最后由 Zack 于 2018-5-31 13:39 编辑最近在搞CentOS7装机的事情&#xff0c;在此记录期间遇到关于网卡方面的坑&#xff0c;整理分享下&#xff0c;以免大家继续再踩。一、在CentOS7默认装完系统之后网卡名称一改之前的名称习惯&#xff0c;网卡名称为enoxxxxx(之前命名规…

Maven——继承和聚合

实际项目中&#xff0c;可能正要构建一个大型的系统&#xff0c;但又不想一遍又一遍的重复同样的依赖元素&#xff0c;这种情况是经常出现的。不过还好&#xff0c;maven提供了继承机制&#xff0c;项目可以通过parent元素使用继承&#xff0c;可以避免这种重复。当一个项目声明…

iframe css练习

转载于:https://www.cnblogs.com/wenhuan/p/4019154.html

.NET常用工具类集锦

不错的地址&#xff1a; http://www.cnblogs.com/flashbar/archive/2013/01/23/helper.html https://github.com/chrisyanghua/MyHelper/tree/master/MyHelper http://www.cnblogs.com/conan87810/archive/2009/03/15/1412529.html http://www.cnblogs.com/ltp/archive/2008/03…

现代控制理论-李雅普诺夫

现代控制理论-李雅普诺夫 单输入单输出系统&#xff08;BIBO&#xff09;的系统函数如下&#xff1a; 则&#xff0c;该系统的能控标准型&#xff08;能空性&#xff09;为&#xff1a; 能观性&#xff1a; 李雅普诺夫下的稳定性&#xff1a; 李雅普诺夫下的渐进稳定性&a…

Linux服务器的gou,开源跨平台移动项目Langou【简介】

Langou简介Langou是一个跨平台(Android/iOS)前端开发框架&#xff0c;核心代码使用C编写&#xff0c;底层基于OpenGL绘图&#xff0c;上层实现了一个精简的排版引擎以及一个JS/JSX运行环境。目标是想实现在此基础上开发GUI应用程序可兼顾开发速度与运行效率。暂时只支持iOS与An…

vue从入门到进阶:简介(一)

前言 用了这么久的vue了&#xff0c;但是一直没有时间写个系列文章&#xff0c;现在抽一定时间总结下vue的知识点。 首先&#xff0c;Vue 不支持 IE8 及以下版本&#xff0c;因为 Vue 使用了 IE8 无法模拟的 ECMAScript 5 特性。但它支持所有兼容 ECMAScript 5 的浏览器。下面总…

linux堡垒机开源软件,Jumpserver开源堡垒机

Jumpserver开源跳板机系统部署1.简介Jumpserver使用Python / Django进行开发&#xff0c;遵循Web 2.0规范&#xff0c;配备了业界领先的Web Terminal解决方案&#xff0c;交互界面美观、用户体验好。Jumpserver采纳分布式架构&#xff0c;支持多机房跨区域部署&#xff0c;中心…

node截图服务可用性报告

2019独角兽企业重金招聘Python工程师标准>>> 前言 服务器端截图可以做什么&#xff1f; 个人观点&#xff1a;省去跟报表有关的EDM开发&#xff0c;直接从系统上截图&#xff0c;然后发图片给用户就搞定。剩下的自己脑补。 既然这么好&#xff0c;为毛不赶紧弄。…

java反射快速入门(二)

上一遍博文 , 简单介绍java 反射的常用接口,本遍博文, 我会结合项目开发的实际例子讲解下 java反射的使用 现在有个需求, 要将一个对象转换成xml格式, 或者将一串xml转换一个对象, 这时我们循序渐进, 先从最简单的入手 一&#xff1a; 方案① 场景 &#xff1a; NBA球员信息描述…

C#QQ邮箱验证

注意&#xff1a; QQ邮箱的简单邮件传输协议&#xff08;SMTP&#xff09;使用了SSL加密&#xff0c;必须启用SSL加密、指定端口。 QQ邮箱POP3/SMTP服务默认是关闭的&#xff0c;需要开启服务&#xff08;设置>账户>开启服务&#xff09;。 QQ邮箱若有独立密码&#xff0…

浅谈ASP.NET框架

本篇文章更适合具有一定开发经验&#xff0c;一定功底&#xff0c;且对底层代码有所研究的朋友&#xff01;&#xff01;&#xff01; 本篇文章稍微偏原理且底层&#xff0c;有一定难度和且比较晦涩&#xff0c;文章粒度稍微粗些&#xff0c;更细粒度的&#xff0c;会在后续的文…

C语言之冒泡排序

假设要对含有n个数的序列进行升序排列&#xff0c;冒泡排序算法步骤是&#xff1a; 1、从存放序列的数组中的第一个元素开始到最后一个元素&#xff0c;依次对相邻两数进行比较&#xff0c;若前者大后者小&#xff0c;则交换两数的位置&#xff1b; 2、第1趟结束后&#xff0c;…

linux sar 历史负载,查看负载、vmstat、top、sar以及nload命令

使用w查看系统负载1.w命令&#xff0c;查看系统负载&#xff1a;单位时间内使用cpu的活动的进程有多少个[rootweix01 ~]# w #load average 后面三个数字表示1分钟&#xff0c;5分钟&#xff0c;15分钟的负载值&#xff0c;最合适的是逻辑cpu数量与1分钟负载一致21:10:21 up 8 m…

linux系统编程:IO读写过程的原子性操作实验

所谓原子性操作指的是&#xff1a;内核保证某系统调用中的所有步骤&#xff08;操作&#xff09;作为独立操作而一次性加以执行&#xff0c;其间不会被其他进程或线程所中断。 举个通俗点的例子&#xff1a;你和女朋友OOXX的时候&#xff0c;突然来了个电话&#xff0c;势必会打…

Intent.createChooser文件选择

实现点击Button选择文件, 在TextView上显示Uri 1 <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"2 xmlns:tools"http://schemas.android.com/tools"3 android:layout_width"match_parent"4 android…