iOS UI布局简史

高能提醒:本文内容是个大杂烩,摘抄引用请见文章末尾的参考资料。另外,加了一些本身的看法!html

平常开发中,UI搭建、调试会占用咱们大部分的时间,以致于移动端开发常常会被调侃为搭界面的。提升UI布局技术能够提升开发效率,把更多的时间放在优化、逻辑方面,而不是被界面业务绑死。react

UI布局技术概览

  • nib:nib是NeXT interface builder的英文缩写,以二进制的形式存储界面信息,是IB3.0之前的文件格式。android

  • xib:xib是xml interface builder的英文缩写,是IB3.0以后苹果公司推出的新一代,以xml格式存储界面信息,在最终执行前,xib文件会被编译为nib文件。。。。。。(请注意大神@史前图 的评论)ios

  • storyboard:故事版文件,是苹果最新推出的用于在界面开发中替代xib文件的一种新技术。本质上是一个xml文件的集中管理区,不但能够描述xib单个界面的结构,还能够描述界面之间的跳转及依赖关系。主要是靠手拖,感受像积木玩具。git

  • frame:等效于代码版的storyboard,但更灵活。目前比较经常使用。若是没有好的适配方案,是多众多机型尺寸仍是有点棘手。(欢迎补充最优雅的适配方案教程地址)程序员

  • AutoLayout:自动布局(AutoLayout)是iOS6发布的界面布局技术,该算法的主要思想是:将基于约束系统的布局规则(本质上是表示视图布局关系的线性方程组)转化为表示规则的视图几何参数。实际上AutoLayout算法自己并不是有🍎发明,只是苹果用Objective-C去实现了该算法,方便iOS开发者使用。AutoLayout有多种使用方式,如①可视化工具:Xcode的Interface Builder,②纯代码:以Masonry为表明。更多内容见自动布局 Auto Layout (原理篇)github

  • FlexBox:弹性布局(Flexible Box)。对,就是目前Web端最流行的布局方式(之前是盒子模型),如今APP上也能使用。此方案就扩展出不少技术,如Yoga(最牛逼的表明,Facebook出品,衍生出不少上层方案,如跨平台的ReactNative、Android的Litho、iOS的Yogakit)、FlexboxLayout(Android表明,Google出品)、FlexLibFLEX等。(欢迎补充)golang

  • swiftUI:官网,苹果官方推荐。更多内容见苹果发布全新 SwiftUI 框架:一次编码,五端通用objective-c

nib

iOS 开发中,搭建界面的一些争论算法

xib

iOS 开发中,搭建界面的一些争论

storyboard

iOS 开发中,搭建界面的一些争论

frame

经过frame编写界面,主要难点在于机型适配,并且还比较繁琐。下面是适配的2个要点:

非刘海机型

很明显能看出这三种屏幕的尺寸宽高比是差很少的,加上如今都屏幕尺寸都是4.7+,所以常以iPhone 6(s)为基准,进行等比缩放。在实际中可能整个页面所有、或部分节点、或仅缩放宽(或高,而后另外一侧自适应) 。

// 在AppDelegate.h中
@property float autoSizeScaleX;
@property float autoSizeScaleY;

// 在AppDelegate.m中
#define ScreenHeight [[UIScreen mainScreen] bounds].size.height
#define ScreenWidth [[UIScreen mainScreen] bounds].size.width
 
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    AppDelegate *myDelegate = [[UIApplication sharedApplication] delegate];
   
    if(ScreenHeight > 667){ // 这里以(iPhone 6)为准
        myDelegate.autoSizeScaleX = ScreenWidth/375;
        myDelegate.autoSizeScaleY = ScreenHeight/667;
    } else {
        myDelegate.autoSizeScaleX = 1.0;
        myDelegate.autoSizeScaleY = 1.0;
    }
}
复制代码

iPhone 6屏幕的高度是667,所以当屏幕尺寸大于iPhone 6时,autoSizeScaleX和autoSizeScaleY即为当前屏幕和iPhone 6尺寸的宽高比。若是手机为Iphone6那么屏幕比例为1,若是为Iphone6s,屏幕比放大,Iphone5就屏幕比缩小。如今咱们获取了比例关系后,先来看一下如何解决代码设置界面时的适配。

CGRectMake(CGFloat x, CGFloat y, CGFloat width, CGFloat height)这个方法使咱们经常使用的设置尺寸的方法,在.m文件中

CG_INLINE CGRect TS_CGRectMake(CGFloat x, CGFloat y, CGFloat width, CGFloat height)
{
    AppDelegate *myDelegate = [[UIApplication sharedApplication] delegate];
    CGRect rect;
    rect.origin.x = x * myDelegate.autoSizeScaleX; 
    rect.origin.y = y * myDelegate.autoSizeScaleY;
    rect.size.width = width * myDelegate.autoSizeScaleX;
    rect.size.height = height * myDelegate.autoSizeScaleY;
    return rect;
}
复制代码

当咱们使用的时候直接这样作UIImageView *imageview = [[UIImageView alloc] initWithFrame:TS_CGRectMake(100, 100, 50, 50)]; 这样咱们得出的就是转换后的坐标了。这个imageview在五、六、6 Plus的位置和尺寸比例都是同样的。

不止是尺寸的适配,还有文字大小的适配。

#define MainScreenWidth [[UIScreen mainScreen] bounds].size.width

#define font(R) (R)*(MainScreenWidth)/375.0
复制代码

因此就会常常看到下面的代码:

self.btnForgetPassWord = [UIButton alloc]initWithFrame:TS_CGRectMake(161, 499, 54, 12);
[self.btnForgetPassWord setFont:[UIFont systemFontOfSize:font(12)]];
复制代码

总之,妈妈不再用担忧屏幕的适配了。

刘海机型

刘海比非刘海的区别在于多了一个安全区域SafeArea,因此最简单的办法是移除非安全区域的尺寸,而后按照非刘海机型进行适配。

经常使用的方法方案就是宏!

#define K_iPhoneXStyle ( (CGSizeEqualToSize(CGSizeMake(414, 896), [[UIScreen mainScreen] bounds].size)) || ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(1125, 2436), [[UIScreen mainScreen] currentMode].size) : NO) )
// 或
#define K_iPhoneXStyle ((KScreenWidth == 375.f && KScreenHeight == 812.f ? YES : NO) || (KScreenWidth == 414.f && KScreenHeight == 896.f ? YES : NO))


// 其余宏
#define KScreenWidth ([UIScreen mainScreen].bounds.size.width)
#define KScreenHeight ([UIScreen mainScreen].bounds.size.height)
#define K_iPhoneXStyle ((KScreenWidth == 375.f && KScreenHeight == 812.f ? YES : NO) || (KScreenWidth == 414.f && KScreenHeight == 896.f ? YES : NO))
#define KStatusBarAndNavigationBarHeight (K_iPhoneXStyle ? 88.f : 64.f)
#define KStatusBarHeight (K_iPhoneXStyle ? 44.f : 20.f)
#define KTabbarHeight (K_iPhoneXStyle ? 83.f : 49.f)
#define KMagrinBottom (K_iPhoneXStyle ? 34.f : 0.f)

#define KScaleWidth(width) ((width)*(KScreenWidth/375.f))
#define IsIphone6P SCREEN_WIDTH==414
#define SizeScale (IsIphone6P ? 1.5 : 1)
#define kFontSize(value) value*SizeScale
#define kFont(value) [UIFont systemFontOfSize:value*SizeScale]
复制代码

只考虑大部分状况其余哈~~例如横屏、新分辨率等就另说。

AutoLayout

和frame比起来灵活性有必定加强,将尺寸影响从总体降为局部,可是在更新时使用起来仍是有必定麻烦,并且新引入优先级的概念。关于更新的几个方法的区别:

  • setNeedsLayout:告知页面须要更新,可是不会马上开始更新。执行后会马上调用layoutSubviews。
  • layoutIfNeeded:告知页面布局马上更新。因此通常都会和setNeedsLayout一块儿使用。若是但愿马上生成新的frame须要调用此方法,利用这点通常布局动画能够在更新布局后直接使用这个方法让动画生效。
  • layoutSubviews:系统重写布局。
  • setNeedsUpdateConstraints:告知须要更新约束,可是不会马上开始。
  • updateConstraintsIfNeeded:告知马上更新约束。
  • updateConstraints:系统更新约束。

更多关于Masonry的使用请移步Masonry使用注意篇

AutoLayout最大的问题在于须要精确的知道每个UI元素的约束关系,当页面约束很复杂的时候,对程序员的细心和耐心是极大的考验。然而这根本不算是最严重的问题,通常页面都由若干个组件拼装而成,AutoLayout最可怕的是不支持热插拔组件,即不能够销毁一个有其余组件依赖该组件约束的组件,程序员若是想要“删除”一个组件,须要添加一个引用指向该组件的宽或高,当须要“删除”时,将该变量设为0,你觉得就这么简单的完了?若是再将该组件“插入”回原处呢?

恰好FlexBox完美的解决了这个问题,请继续日后看。

我从15年开始转iOS,当时跳过xib、storyboard,直接学习的用Masonry纯代码式布局,因此我到如今也不会Interface Builder。Masonry给个人感受是比较枯燥的,没有所见即所得的体验,并且一个VC或View里UI代码占用了很大部分。可是熬过初级后,和其余同事协同开发、灵活性、可控性、抽象复用等方便的体验是很是棒的!

FlexBox

终于轮到今天的主角了!开心~~有一点Web基础的能够去Flexbox布局详解学习和练习。

Flexbox解决了什么?

  • 方向性 (传统布局方向是从左到右,从上至下)
  • 弹性伸缩 (传统尺寸定义是经过像素等来精肯定义)
  • 元素对齐(能够作到插拔)

从上述几点看来,它彷佛完美的解决了iOS原生布局开发效率低的问题,但它会增长页面的嵌套层级关系,在硬件性能饱和的状况下用空间换取开发效率。

我相信你对它的效率有疑虑!?(大神@史前图 的评论里指出AutoLayout的性能已经更新,因此请执行搜索相关最新的资料😄)

这里根据从AutoLayout的布局算法谈性能里的测试代码进行修改,对Frame/AutoLayout/FlexBox进行布局,分段测算10~350个UIView的布局时间,取100次布局时间的平均值做为结果,耗时单位为秒。结果以下图:(测试布局的项目代码GitHub地址

虽然测试结果不免有误差,可是根据折线图能够明显发现,FlexBox的布局性能是比较接近 Frame的。60FPS做为一个iOS流畅度的黄金标准,要求布局在0.0166667s内完成,AutoLayout在超过50个视图的时候,可能保持流畅就会开始有问题了。本次测试相关配置:Xcode9.2,iPad Pro (12.9-inch)(2nd generation) 模拟器。

Yoga

Yoga最初源自Facebook在2014年的一个开源的CSS布局开源库,在2016年通过修改,改名为 Yoga。它是由C语言实现,基于Flexbox的一个编写视图的跨平台代码,让布局变得更简单,支持多个平台,包括Java、C#、C、Objective-C和Swift。

Yoga Layout 官网。库开发者能够集成 Yoga 到他们的布局系统,就如Facebook 已经集成进了它的两个开源项目:React NativeLithoComponentkit。另外iOS开发者能够直接用YogaKit来布局视图的框架。

React Native

RN就很少说,目前市场上不少APP都在使用,应该说是APP跨平台开发的不二选择:

Litho

Litho is a declarative framework for building efficient user interfaces (UI) on Android. It allows you to write highly-optimized Android views through a simple functional API based on Java annotations. It was primarily built to implement complex scrollable UIs based on RecyclerView. With Litho, you build your UI in terms of components instead of interacting directly with traditional Android views. A component is essentially a function that takes immutable inputs, called props, and returns a component hierarchy describing your user interface.

Litho是高效构建Android UI的声明式框架,经过注解API建立高优的Android视图,很是适用于基于Recyclerview的复杂滚动列表。Litho使用一系列组件构建视图,代替了Android传统视图交互方式。组件本质上是一个函数,它接受名为Props的不可变输入,并返回描述用户界面的组件层次结构。

Litho是一套彻底不一样于传统Android的UI框架,它继承了Facebook一贯大胆创新的风格,突破性地在Android上实现了React风格的UI框架。架构图以下:

我对Android开发不熟,因此请移步 基本功 | Litho的使用及原理剖析

YogaKit

iOS端Yoga的上层UI库Componentkit,可是我看文档以后以为很是难用,因此略过。

可是YogaKit还不错,同时支持OC和Swift,Yoga 教程-使用跨平台布局引擎 这份基于Swift的YogaKit教程还不错。

ps:我本想找一个Masonry的替代者,特别但愿能支持Flex布局,因此抱有很大但愿去了解和学习YogaKit,可是失望😞了。第一是代码繁琐,第二是YogaKit的使用者很少。我仍是好好研究RN吧~

FlexboxLayout

FlexboxLayout是谷歌出的,只支持Android,因此期待各位大神关于此框架的评论。

顺便吐槽一句,google是看着什么语言和技术火,都会插一脚,而后独自开发一套。如golang、angular、android studio、dart、flutter等,加上国内技术开发者的google情节,因此大家本身体会。。。除了JS引擎——V8

swiftUI

iOS上的UI,我以为swiftUI才是之后的王者!我不接受反驳,哈哈哈哈哈哈...iOS的UI开发语言就objective-c和swift,从编译型的oc变为解释型的swift,从语言角度看跨度仍是挺大的,在众多技术均在快速发展的现代,解释型语言更能适应将来,不过swift还未在跨平台上发挥出任何两点,就连在iPhone和mac上都没。

若是没有swift的从入门到再入门事件,可能swift的市场又是另一番景象!真但愿swift 5能稳定下来。

后语

UI的基础布局也就那么回事,都是从图形绘制OpenGL,到UI Library,再到UI Controls,再到APP,电脑发展到如今一直没有变过,如Windows上的MFC、iOS上的UIKit、刚出来的flutter等。

此处借鉴TCP/IP的七层模型(我以为这是世界上最牛逼的架构,没有之一,不接受反驳!),只有分层以后,不一样的人员才能扮演不一样的角色,去完成对应的工做。咱们说的UI是软件层面的,是运行在硬件上的,因此软件到硬件的衔接要靠图形绘制,这个工做是由操做系统去完成。

有了操做系统这个大环境,为了创建生态,必须对外提供响应的开发套件,如UI库、网络库、驱动库等,这一点在Windows提现特别明显。而后开发者才会加入你的开发阵营,而后你的市场才会逐步扩大,因此为啥常常据说一门语言和技术背后,也须要强大的公司和资金来支持,好比微软、谷歌、亚马逊、Facebook、众多第三方厂商的SDK等等,请注意像阿里云SDK、腾讯SDK等各个厂商也算是这一层的,能够把Windows、Android、iOS等操做系统看着是一级厂商,把Facebook、阿里云、腾讯云等服务提供商是二级厂商。

有了各个等级厂商提供的Library和对应的Control,而后才能更好的创造出百花齐放的APP,才有咱们这种出现不一样方向的软件开发者。因此看待一个新的UI库或技术,须要从其原理和应用分析,找到其合适的定位,若是你没有深刻分析背后的技术,是没法发挥其最大价值的。

就像React Native,你特么叫我去作IM和多媒体,老子一巴掌给你飞过来!RN它只是写下降了APP UI的门槛,扩大了其受众者,就如React的口号『learn once write anywhere』。RN的大体原理是经过JavaScript和JavaScript解释器,去动态控制原生的UI布局,和之前有大神经过解析XML去自动生成UI,是同样的道理,又如Lua这个同JavaScript语法相似的脚本在游戏行业活得风生水起,RN的热更新原理就是这么来的——经过更新JavaScript文件达到更新UI布局和业务逻辑等目的,因此RN的核心是在具备ES 6/7/8/...的JavaScript和对应的JavaScript解释器,关于RN中的JavaScript解释器,能够看看逆袭Futter? Facebook 发布全新跨平台引擎 Hermes!JS引擎大PK:JSC vs V8 vs Hermes

不限于RN,你想要作得更好更优秀,你须要多研究。不要想着你会React网页,就以为能够来作APP,呵呵,一个库依赖问题就能把你搞死。不是你长的美,就能够想得美!就比如让你用openGL的API来画一个控件,你画很差,而后就说openGL技术不行?!这时我只能送你一个字,滚!

说了这么多,我不是但愿任一一个UI库有多牛逼,而是但愿FlexBox这个UI规范能在APP端能扩大影响,尽可能和在布局上更优秀的Web端保持一致,最终实现统一,作到最根本的跨平台,可是能够有不少库或者方案来实现。




2019-07-28 更新: 下面评论 @小二Flutter 提到的MyLinearLayout也很优秀很强大,新旧布局方案均兼容,各位技术官能够去尝试一下,说不定你也喜欢。可是我以为文档不是完善,特别是使用方面的,会致使上手难度增大。

下面评论 @史前图腾 提到的iOS布局历史,本文中提到的有些不对,请注意甄别!(我想修改,可是不知道怎么修改😔)。



参考资料:(排名不分前后)

相关文章
相关标签/搜索