前言:这篇文章是笔者在项目中对布局技术进行技术选型和应用的相关介绍,供大家参考。

Question1:什么是autoLayout?

Answer1: autolayout是苹果从iOS6开始推出的旨在优化、简化UI布局相关工作的新框架,其理念是抽象出约束的概念,将其作用于view,而不再需要手动设置其frame。

个人理解其中的分别就好像面向对象编程和面向过程编程之间的分别;能够体会面向对象编程的好处,我们也不难领会autolayout带来的变化:我们唯一需要处理的,就是约束。其后的一切工作,苹果帮你搞定。

Question2:为何要引入自动布局?

Answer2: 传统的frame设置方式在面对碎片化的屏幕分辨率显得力不从心;也难以应付旋转屏等高阶场景。约束的抽象让你从分辨率的适配工作中解脱出来,只需要了解(或者说抽象出)view所需要的约束,就可以获得一个理想的布局。否则,你需要计算很多难以理解和维护的硬编码,这不仅不优雅,而且很容易出错,可读性和可维护性都相对较差。

当前iphone开发分辨率:

iphone4/4s :320*480

iphone5/5c/5s: 320*568

iphone6: 375*667

iphone 6 plus: 414*736

Autolayout技术:

从iOS6问世起(2012年下半年),苹果推出了autolayout技术,并开始大力推广其应用。Autolayout的api随着版本更迭不断的完善,业界也出现了很多第三方封装的自动布局api框架。我们产品支持iOS7+,在系统支持方面是没有任何障碍的(注意不要使用iOS8+的api即可,后面会进一步说明)。

1.    autoLayout相关技术概览:

2.    NSLayoutConstraintSDK API;

3.    Visual FormatLanguage;

4.    Apple Interface Builder;

5.    第三方框架:masonry, purelayout, sdautolayout 等。

6.    NSLayoutAnchorSDK API。

NSLayoutConstraint SDK API

苹果推出的基础api,只要理解了autolayout的概念,也很容易理解其使用,但其缺点是接口非常冗长,使用麻烦,也缺少组合的快捷接口,对于开发者来说不够友好。

例(设置一个页面水平居中的约束):

[self.view addConstraint:[NSLayoutConstraint

constraintWithItem:btn

attribute:NSLayoutAttributeCenterX

relatedBy:NSLayoutRelationEqual

toItem:self.view

attribute:NSLayoutAttributeCenterX

multiplier:1

constant:0]];

 Visual Format Language

 

苹果推出的一种格式标记语言,专门用于描述布局关系。

例:

//水平方向

NSString *hVFL=@"H:|-20-[redView]-30-[blueView(==redView)]-20-|";

NSArray *hCons =[NSLayoutConstraintconstraintsWithVisualFormat:hVFL options:NSLayoutFormatAlignAllTop |NSLayoutFormatAlignAllBottom metrics:nilviews:@{@"redView":redView,@"blueView":blueView}];     [self.view addConstraints:hCons];

//垂直方向

NSString *vVFL=@"V:|-20-[redView(50)]";

NSArray *vCons =[NSLayoutConstraintconstraintsWithVisualFormat:vVFL options:0 metrics:nilviews:@{@"redView":redView}];

[self.view addConstraints:vCons];

该方式看上去比较科幻,需要对其格式标记语言有深入了解之后才可以熟练使用;这种代码阅读起来主要靠脑补,画面太美。

根据资料显示,VFL语言对于某一些场景的自动布局不支持,且调试比较困难,可读性很差,学习成本高。

不推荐在项目中使用该技术(有兴趣的话可以用来学习和研究)。

AppleInterface Builder:

 

苹果的图形化编辑器。在其中可以方便、快速的设定约束(多用ctrl键)。

对于一次成型的view来说,此方式的优势还是显而易见的;推荐和xib一起使用。

Tips:

1.    建议对view进行命名,否则界面稍微复杂起来很容易将约束搞混。

2.    约束也可以作为outlet,用于后续变更,也可以用来做动画,很方便。

第三方框架:

 

第三方框架封装的出发点主要是希望能够快速、可靠的使用代码来进行autolayout布局;在封装的过程中尽可能保持原生autolayout的全部能力。

最有名的框架是masonry,在github上1W+ stars.

https://github.com/SnapKit/Masonry

我在当前项目中引入的框架:pureLayout

https://github.com/PureLayout/PureLayout

masonry的特点是其简洁的链式语法;而pureLayout则更加保持了oc的语法习惯。这两个库都非常成熟。

之所以选择pureLayout,更多的是出于个人喜好和习惯;在我一年多的使用过程和学习经验来看,该库的学习成本非常低,能够快速上手使用,api风格接近原生,也比较可靠稳定。

NSLayoutAnchor SDK API

 

iOS 9.0+。

API对比示例:

// Creating constraints usingNSLayoutConstraint

[NSLayoutConstraint

constraintWithItem:subview

attribute:NSLayoutAttributeLeading

relatedBy:NSLayoutRelationEqual

toItem:self.view

attribute:NSLayoutAttributeLeadingMargin

multiplier:1.0

constant:0.0].active = YES;

[NSLayoutConstraint

constraintWithItem:subview

attribute:NSLayoutAttributeTrailing

relatedBy:NSLayoutRelationEqual

toItem:self.view

attribute:NSLayoutAttributeTrailingMargin

multiplier:1.0

constant:0.0].active = YES;

// Creating the same constraints usingLayout Anchors

UILayoutGuide *margin =self.view.layoutMarginsGuide;

[subview.leadingAnchorconstraintEqualToAnchor:margin.leadingAnchor].active = YES;

[subview.trailingAnchorconstraintEqualToAnchor:margin.trailingAnchor].active = YES;

可以看到,这里的api调用简单了很多。看来苹果也已经认识到了其api的冗长,对于开发者不够友好,因此对其做了二次封装。但此api 是iOS9+,因此我们当前项目中无法使用。不过这不影响我们自行去体验和学习其api。

官方文档:

https://developer.apple.com/library/ios/documentation/AppKit/Reference/NSLayoutAnchor_ClassReference/index.html

务实的选择

罗列了上面的这些技术,我们就可以大致的选择我们的技术脉络了。NSLayoutAnchorSDK API因为系统限制,当前还不能使用;

NSLayoutConstraintSDK API虽然是原生,但开发成本过高,也不适合选择;

VFL语言有其固有缺陷(主要是可读性和维护性方面),也不建议在正式项目中使用;

我们可以在项目中根据实际情况,结合使用第三方的框架(适用于代码编写的view)和Interface Builder(xib的view)这两种方式。而具体对于某一个view来说,只使用一种方式(代码或者xib)来进行自动布局是相对安全且易于维护的方式。

约束类型介绍:

1.    长/宽,也就是其size

2.    设置距离:比如a view的最右边和b view的最左边之间的距离。

3.    设置居中(或居中的距离),比如 a view的x center和b view的 x center相等,或者两者之间的差值是多少。

4.    iOS 8+苹果对view增加了margin(边缘)的概念,因此autolayout的2和3也相应的增加了边缘相关的api,即将之前的实际边界替换成边缘,然后再取理解就ok. 我们的系统支持iOS7+,因此请务必不要使用此类api.

简单布局示例(使用purelayout):

- (void)setupButtonsConstraints

{

if ([self.buttonscount] < 2 && [self.buttonscount] > 0)

{

UIButton *button = self.buttons[0];

[button autoPinEdgesToSuperviewEdges];

}

else

{

[self.buttonsautoMatchViewsDimension:ALDimensionWidth];

[[self.buttonsfirstObject] autoPinEdgeToSuperviewEdge:ALEdgeLeft];

UIButton *previousView = nil;

for (UIButton * btn inself.buttons)

{

[btn autoAlignAxisToSuperviewAxis:ALAxisHorizontal];

[btn autoPinEdgeToSuperviewEdge:ALEdgeTop];

[btn autoPinEdgeToSuperviewEdge:ALEdgeBottom];

if (previousView)

{

[btn autoPinEdge:ALEdgeLefttoEdge:ALEdgeRightofView:previousView];

}

previousView = btn;

}

[[self.buttonslastObject] autoPinEdgeToSuperviewEdge:ALEdgeRight];

}

}

这里对一组button(其数量是变化的)设置了约束,它们宽度固定,水平排列,两两相连,左右都顶到了view的最边缘。

对于一般的view来说,4个约束可以固定一个view。可以想象一下,你的view能否同时满足这几个条件,满足这几个条件以后它是不是就动不了了。

框架使用最佳实践:

学习和研究第三方库中的示例代码和api说明,能够帮助我们快速的掌握其api使用;如果有必要可以深入其源代码了解其中的细节。一般来说,其示例代码中的api调用方式是相对标准和安全的,值得我们参考和借鉴。

One more thing(关于autolayout的错误调试:)

autolayout错误会打印如下:

Unable to simultaneously satisfy constraints.     Probably at least one of the constraintsin the following list is one you don't want. Try this: (1) look at eachconstraint and try to figure out which you don't expect; (2) find the code thatadded the unwanted constraint or constraints and fix it. (Note: If you'reseeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer tothe documentation for the UIView propertytranslatesAutoresizingMaskIntoConstraints) (    "<NSAutoresizingMaskLayoutConstraint:0x887d630 h=--&v=--& V:[UIButtonLabel:0x886ed80(19)]>",    "<NSAutoresizingMaskLayoutConstraint:0x887d5f0 h=--&v=--& UIButtonLabel:0x886ed80.midY == + 37.5>",     "<NSAutoresizingMaskLayoutConstraint:0x887b4b0h=--& v=--& V:[UIButtonLabel:0x72bb9b0(19)]>",     "<NSAutoresizingMaskLayoutConstraint:0x887b470h=--& v=--& UIButtonLabel:0x72bb9b0.midY == - 0.5>",     "<NSLayoutConstraint:0x72bf860V:[UILabel:0x72bf7c0(17)]>",     "<NSLayoutConstraint:0x72c2430UILabel:0x72bfad0.top == UILabel:0x72bf7c0.top>",     "<NSLayoutConstraint:0x72c2370UILabel:0x72c0270.top == UILabel:0x72bfad0.top>",     "<NSLayoutConstraint:0x72c22b0V:[UILabel:0x72bf7c0]-(NSSpace(8))-[UIButton:0x886efe0]>",     "<NSLayoutConstraint:0x72c15b0V:[UILabel:0x72c0270]-(NSSpace(8))-[UIRoundedRectButton:0x72bbc10]>",     "<NSLayoutConstraint:0x72c1570UIRoundedRectButton:0x72bbc10.baseline ==UIRoundedRectButton:0x7571170.baseline>",     "<NSLayoutConstraint:0x72c21f0 UIRoundedRectButton:0x7571170.top== UIButton:0x886efe0.top>" )

这里的约束看起来很难理解,应该是打印了类似VFL的约束表示。

我在项目中引入了NSLayoutConstraint+Description,重写了其description方法,这样在出错时可以容易的阅读当前出错的约束情况,加以鉴别。

附录:Autolayout出现前的iOS布局技术

关于旋转屏:

对于iphone应用开发者来说,绝大部分应用都是不需要支持旋转屏幕的;苹果的系统应用倒是有几个支持转屏(不过也主要是简单列表的布局,支持起来比较容易)。Iphone的长宽比例相差较大,因此如果要得到一个比较良好的体验,横屏和竖屏的布局一般都需要重新设计,由此带来了巨大的工作量;从用户体验来说也看不到支持横屏的必要性。因此,对于iphone应用来说,绝大部分应用都是不支持旋转屏幕的。大家可以看一下手机里的流行应用(微信、支付宝、网易新闻等),可能只有一些视频类应用的个别页面会支持转屏(播放视频横屏体验更佳)。

而对于iPad来说,其长宽比例较为接近(4:3),且苹果一开始就建议iPad应用开发者适配横竖屏以提升用户体验(横屏使用iPad对用户来说很平常,这点和iphone差别较大)。因此,对于iPad开发者来说,因为转屏场景的存在,布局适配一直是开发中需要注意的一个重点问题。

固定frame写法:

写死frame来布局,在只有320*480一套分辨率的时候非常happy; frame无需计算;  在iphone5推出之前(2012年9月发布),写死frame来布局UI是非常方便快速的;而对于iphone开发者来说,一般不需要考虑屏幕旋转的问题(上面我们已经说了,大部分app是锁定屏幕方向的)。这个时代的iphone 开发者是非常幸福的(android开发者需要适配碎片化的分辨率)。但iphone5、iphone6、iphone6plus带来的分辨率碎片化让固定 frame写法增加了很大的工作量,且代码难以阅读和维护。

Autoresizing技术:

就是在创建视图的同时给出其相对于父视图的“对齐方式与缩放系数”,即autoresizingMask。当父视图发生变化时,通过每个子视图的 autoresizingMask即可自动得出子视图的位置。

然而autoresizingMask的问题在于:

1.    其描述界面变化规则不够灵活,很多变化规则根本无法精确描述。autoresizingMask缩放比例是UIKit内部计算的,开发者无法指定缩放比例的精确值;且一般情况下,距离往往比比例更加精确(这点大家和设计同学沟通的时候应该有体会)。

2.    变化规则只能基于父视图与子视图之间,无法建立同级视图或者跨级视图之间的关系。

总结:Autoresizing用来简单的指定和父view之间的关系还是比较方便的。其在我们当前的项目中使用的也比较多,但它的局限性决定了它只能作为frame布局的辅助,应用于一些简单场景,对于复杂多样化的布局力不从心。在autolayout问世以前,通过autoresizing也可以处理一些简单页面的旋转屏布局(在细节要求不高的情况下)。

AutoLayout技术选型和应用相关推荐

  1. 前端技术选型的遗憾和经验教训

    我是Max,Spectrum的技术联合创始人.Spectrum 是一个面向大型在线社区的开源聊天应用程序,最近被GitHub收购.我们是一个三人团队,主要拥有前端和设计背景,我们在这个项目上工作了近两 ...

  2. 宅家学习,如何进行Kubernetes Ingress控制器的技术选型?

    导语:在Kubernetes的实践.部署中,为了解决 Pod 迁移.Node Pod 端口.域名动态分配等问题,需要开发人员选择合适的 Ingress 解决方案.面对市场上众多Ingress产品,开发 ...

  3. 小米资深工程师瞿晋萍(男):米聊服务器的技术选型和架构设计

    小米资深工程师瞿晋萍:米聊服务器的技术选型和架构设计 - 资讯频道 - CSDN.NET 小米资深工程师瞿晋萍:米聊服务器的技术选型和架构设计 2012-07-07 11:04 | 238次阅读 | ...

  4. 银行背景下分库分表技术选型

    业务持续增长带来的单表数据量过大,必然影响到数据库的读写性能,那到底要不要分库分表呢? 阿里巴巴P3C规范给出一个推荐: [推荐]单表行数超过500万行或者单表容量超过2GB,才推荐进行分库分表. 说 ...

  5. 从数仓到数据中台,谈技术选型最优解

    本文根据颜博老师在[Deeplus直播第218期]线上分享演讲内容整理而成. 颜博 马蜂窝数仓研发总监 现任马蜂窝数据仓库团队负责人,曾供职于京东.IBM.亚信等公司. 数据行业老兵一名,历经传统数据 ...

  6. 麦司机博客项目技术选型-Java后端

    麦司机博客项目 博客主页:maisiji.cn/ github地址:github.com/fendoudebb/- Java后端技术选型介绍 SpringBoot: 后端框架 项目主页: spring ...

  7. .net项目技术选型总结

    做.net开发已经几年了,也参与开发了很多大大小小的项目,所以现在希望总结出一套开发.net项目的常用技术,也为以后做项目技术选型的时候作为参考. 数据库 小型项目:SQLite(工具) 中大型项目: ...

  8. android progressbar 不显示_Android多线程技术选型最全指南(1)

    码个蛋(codeegg) 第 935 次推文 作者:qing的世界 链接:https://juejin.im/post/5d1eb4acf265da1bb003de71 前言 前段时间在组内做了一下现 ...

  9. 如何0代码、快速定制企业级NLP模型?百度工程师详解技术选型与模型调优策略...

    主讲人 | 龙心尘 百度NLP资深研发工程师 量子位编辑 | 公众号 QbitAI 近几年以预训练为代表的NLP技术取得了爆发式发展,新技术新模型层出不穷.企业与开发者如何将最先进的NLP领域科研成果 ...

最新文章

  1. 声明一个图书类(Java)
  2. struts2 用form取值时出现的错误
  3. 手把手教你定制标准 Spring Boot starter
  4. Inception SQL审核注解
  5. nextcloud 中文乱码解决方案
  6. mybatis中foreach标签详解
  7. BZOJ 1692: [Usaco2007 Dec]队列变换( 贪心 )
  8. GraalVM上的Picocli:极快的命令行应用程序
  9. Gitlab 从 12.1 版本开始将不再支持 MySQL !!!
  10. 字符串类习题、面试题详解(第二篇)
  11. 怎样改动、扩展并重写Magento代码
  12. 大学计算机四级报名,2016下半年安徽理工大学计算机四级报名
  13. Linux上层应用--Shell scripts基础规范
  14. Java的ActiveX控件_注册ActiveX控件的几种方法 - 镜花水月 - JavaEye技术网站
  15. pygame编写井字棋游戏
  16. Hyperledger Fabric系统架构
  17. 忍者必须死代码 免费
  18. 理解Memcached缓存[转载]
  19. c语言编程复制快捷键,C语言再学习 -- 常用快捷键
  20. Python蓝桥杯基础之星期一

热门文章

  1. Linux嵌入式基础知识
  2. java专业学校排名_计算机类专业高校排名,想进IT行业,这些学校不可错过!
  3. Twemproxy – Twitter 开源的 Redis proxy
  4. 蓝牙模块教程|一文看懂BLE蓝牙模块应用开发,快速入门指南
  5. 是科学还是魔法?Informer on MindSpore——时间序列预测技术实践
  6. 第七届蓝桥杯本科B组省赛 最大比例
  7. 电脑重装系统后鼠标动不了该怎么解决
  8. IBM的APAR搜索入口地址
  9. 探寻Cat.1和NB-IoT的发展方向
  10. npoi设置Excel边框