屏幕适配小结
一、纯手动之Autolayout
1、VFL语言添加约束
- VFL(Visual format language)语言是苹果为了简化手写Autolayout代码所创建的专门负责编写约束的代码。为我们简化了许多代码量。
2、使用步骤
使用步骤同手动添加约束保持一致
- 创建控件
- 添加到父控件
- 禁用Aoturesizing
- 添加约束
3、使用方法
- 这里先展示一个实例:
NSArray *blueHArr = [NSLayoutConstraint constraintsWithVisualFormat:
@"H:|-20-[blueView]-20-|"
options:kNilOptions
metrics:nil views:
NSDictionaryOfVariableBindings(blueView)];
方法介绍:
constraintsWithVisualFormat
:这个方法返回了一个数组;
@"H:|-20-[blueView(100)]-20-|"
:这句话表明所添加的约束,H
的意思是水平方向添加约束,blueView 视图名称,(100)
代表着blueView 的宽
为100
,blueView
距离父类的左边20,距离父类的右边是20;
options
:是对其方式;
metrics
:返回的是一个字典,它的意思是可以将约束中的值用某些字符串来代理,然后在这个字典中给多对应的字符串赋值
方便修改,并且增加可读性;
views
:返回的也是一个字典,这个字典的意思是:你可以将前面的view用其他字符串来代替,在这里在给他赋给对应的vie
w的名字。
我可以将上面的约束语句改成如下这样:
NSArray *blueHArr = [NSLayoutConstraint
constraintsWithVisualFormat:@"H:|-aa-[cccc(100)]-20-|"
options:kNilOptions
metrics:@{@"aa":@20}
views:@{@"cccc":blueView}];
-
这里我用aa替换了20,cccc替换了blueVuew
这里有一个简单的方法,就是使用NSDictionaryOfVariableBindings(blueView)来替换views中的内容也是可以的。
4、VFL的缺点
- VFL语句
不支持乘除法
- 比如我想表示redview是blueview高度的一半,
我们是不能
这样写的:
NSArray *redVArr = [NSLayoutConstraint
constraintsWithVisualFormat:@"V:[blueView]-20-[redView(==blueView*0.5)]"
options:NSLayoutFormatAlignAllRight
metrics:nil
views:NSDictionaryOfVariableBindings(blueView, redView)];
原因就是这里包含了乘法,而一旦VFL语句中包含了乘除法
那么系统就会不识别而崩溃。
- 所以,当一涉及到乘除法的时候,我们又不得不再次使用系统原来的方法中来:
NSLayoutConstraint *redWidth = [NSLayoutConstraint
constraintWithItem:redView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:blueView
attribute:NSLayoutAttributeWidth
multiplier:0.5
constant:0.0];
5、关于Autolayout还有一个叫Masonry的框架
不支持乘除法
我们是不能
这样写的:
NSArray *redVArr = [NSLayoutConstraint
constraintsWithVisualFormat:@"V:[blueView]-20-[redView(==blueView*0.5)]"
options:NSLayoutFormatAlignAllRight
metrics:nil
views:NSDictionaryOfVariableBindings(blueView, redView)];
原因就是这里包含了乘法,而一旦VFL语句中包含了乘除法
那么系统就会不识别而崩溃。
NSLayoutConstraint *redWidth = [NSLayoutConstraint
constraintWithItem:redView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:blueView
attribute:NSLayoutAttributeWidth
multiplier:0.5
constant:0.0];
Masonry 源码:https://github.com/Masonry/Masonry
Masonry是一个轻量级的布局框架 拥有自己的描述语法 采用更优雅的链式语法封装自动布局 简洁明了 并具有高可读性 而且同时支持 iOS 和
Max OS X。
我们先来看一段官方的sample code来认识一下Masonry
[view1 mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(superview).with.insets(padding);}];
看到block里面的那句话: make edges equalTo superview with insets
通过链式的自然语言 就把view1给autolayout好了。
Masonry是目前最流行的AutoLayout框架.
- 使用:将Masonry文件包拖入项目,删掉自带的info.plist文件.demo中对Masonry的引用在.pch文件中.
- 使用Masonry不需要设置
控件的translatesAutoresizingMaskIntoConstraints属性为NO;
Masonry简单实现
(左下角正方形):
[targetView mas_makeConstraints:^(MASConstraintMaker *make) {
make.bottom.equalTo(self.view).offset(-20);
make.leading.equalTo(self.view).offset(20);
make.size.mas_equalTo(CGSizeMake(100, 100));
}];
内边距为50:
- 第一种实现方式
make.leading.top.mas_equalTo(@50); make.trailing.bottom.mas_equalTo(@-50);
- 第二种实现方式
make.edges.insets(UIEdgeInsetsMake(50, 50, 50, 50));
Masonry使用技巧:
定义以下两个宏,在使用Masonry框架时就不需要加mas_前缀了
(定义宏一定要在引入Masonry.h文件之前).
//define this constant if you want to use Masonry without the ‘mas_‘ prefix
#define MAS_SHORTHAND
//define this constant if you want to enable auto-boxing for default syntax
#define MAS_SHORTHAND_GLOBALS
使用Masonry添加兄弟控件约束不需要考虑父控件.
具体实现代码如下:
[leftView mas_makeConstraints:^(MASConstraintMaker *make) {
make.leading.offset(20);
make.bottom.offset(-20);
make.trailing.equalTo(rightiew.leading).offset(-20);
make.height.equalTo(100);
make.height.equalTo(rightiew.height);
}];
[rightiew makeConstraints:^(MASConstraintMaker *make) {
make.trailing.equalTo(self.view.trailing).offset(-20);
make.top.equalTo(leftView.top);
make.width.equalTo(leftView.width);
}];
二、xib(storyboard)进行约束
如题,利用xib文件为控件添加约束,storyboard方法一样,大家都懂得,之前的Xcode只有xib没有storyboard,storyboard当然会和xib方法一样了,使用xib的时候(记住不要勾选Use
Autolayout )下面切入正题,如何用xib为控件添加约束。
1.添加约束主要用到下面的三个部分:
从左到右:align、pin、resolve auto layout issues。单词的意思可能有同学不是很理解,不担心,不懂就点开试一下,是什么,一试便知。
(1)、align
第一个模块主要是对齐的,那么对齐就要多个控件对齐,譬如:两个字空间左对齐、下对齐、X轴对齐、字控价和父控件中心对齐等,使用align主要是考虑多个控价对齐问题。
(2)、pin
第二个模块主要是单个控件的属性,控件在父控件中的位置,控件的宽高等,主要是针对一个控件而言的。
(3)、resolve auto layout issues
第三个模块主要是对约束进行编辑的,包括删除,添加,重置约束等。
2.添加约束的几个规则:
情况1:约束控件距离父控件的四周的距离。
第一种比较简单,也比较好理解,一个控件的上下左右的距离都控制好了,控件也就控制好了,如果你切换不同的屏幕时,控件距离屏幕边框的距离不变,会改变控件的大小。
xib中还是正方形的,但是当iPhone的屏幕上,变形了。
此处大家注意一个点,如果你是一个普通控件,像button,image view(已添加图片),label等,这些控件,当我们只给他添加三个约束时,软件不会报错,这是因为控件中有内容,软件会自适应大小,会根据内容的大小来改变控件的大小,这样虽然没有报错,但是控件的大小已经不是我们想要的大小了。。。但是对于一个view来说,你只给他控制三个边,软件会报错的,软件不知道最后一条边距离父控件多远,所以他会报错。所以,要想准确控制一个控件,就要确保确定的大小或者XY值。
情况2:控制控件相邻的两条边距离父控件的距离和控件的宽高。
控制控件相邻的两条边距离,也就控制了控件的左上角的(x,y),控制控件的宽高,也就控制了控件的右下角的(x,y),这样就能控制控件了。
情况3:控件XY轴居中,固定控件宽高。
如果只控件XY轴居中,还是那句话,一般控件像button,image view(已添加图片),label等,软件不会报错,并会自适应大小,但是大小会改变,对于view就会报错,软件给不出控件的大小。
情况4:控件X或Y居中,另一个方向的边距离父控件的距离,宽高。
建议:建议大家在写demo的时候用view,如果用其他的控件,可能会有些问题不报错,但是用view就会暴露出来。
关于xib(storyboard)的适配详细的可以参考下篇博客:
http://justsee.iteye.com/blog/2148987
三、像素适配
以上说的两点都是屏幕大小适配,也就是我们常说的屏幕自适应仅仅只是坐标和大小的适配,避免出现严重的bug和控件溢出等现象,现在要谈的便是像素适配,也就是根据用户所用的机型信息判断出是什么设备,从而提供相应的@xx图片。
目前在iPhone的阵营中,iphone4~6s图片均采用@2x,只有6 plus&6s plus采用@3x。所以可以进行机型的判断从而使用正确的图片。
三种常用的办法获取iOS设备的型号:
1. [UIDevice currentDevice].model (推荐);
2. uname(struct utsname *name) ,使用此函数需要#include ;
3.sysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp,
size_t newlen) ,使用此函数需要#include ,#include;
推荐使用第一种方法,为最上层的API,在项目开发中推荐使用高级的API ,因为其识别度高,更简洁易用。2、3两种都是BSD级别的API ,为底层的API,不推荐。
示例:
1. NSString * strModel = [UIDevice currentDevice].model ;
2. struct utsname systemInfo
uname(&systemInfo)
NSString * strModel = [NSString stringWithCString:systemInfo.machine
encoding:NSUTF8StringEncoding];
3. size_t size
sysctlbyname ("hw.machine" , NULL , &size ,NULL ,0)
char *model = (char *)malloc(size)
sysctlbyname ("hw.machine" , model , &size ,NULL ,0)
NSString * strModel = [NSString stringWithCString: model
encoding:NSUTF8StringEncoding];
获取了设备型号之后,还不能准确的了解其设备类型,还需要找到与其型号对应的设备说明。
该链接为各机型设备信息对应表 : https://www.theiphonewiki.com/wiki/Models
此外,因为苹果现在的手机的长宽比并未改变依旧是16:9,所以我们可以在准备素材的时候,以点为单位,而不是像素。非矢量素材,就可以做尺寸最大的,之后再进行缩小。比如你需要兼容3x的屏幕,就直接做最高那种图片。因为之后几种机型长宽比都是9:16,可以直接拉伸。已有非矢量素材,直接拉伸放大到@3x。矢量图就直接做点那个尺寸。比如44
x 66个点的按钮。就建立一个44 x 66的场景。之后再导出成2倍图,3倍图,因为矢量放大不失真。不要建立一个3x的场景,导出成大图片,再进行缩小,这样就容易失真。
以下为这方面的资料可以参考一下
《iPhone屏幕适配,历史及现状》http://hjcapple.github.io/2014/10/10/iphone-screen.html
《APP设计师必读-快速适配iPhone6及plus的诀窍》http://www.ui.cn/project.php?id=25685
《iPhone6分辨率与适配》http://www.cocoachina.com/ios/20140912/9601.html
总结:
以后我们再开发的时候,要使用autolayout,减少frame的使用,这样更方便屏幕的适配,要尽量使用点这个单位进行思考,而不要使用像素。比如,你需要做44 x 66个点的按钮,2x模式,就乘以2, 3x模式就乘以3。这样的思考方式可以大致估计到真实的物理长度。44个点,就是手机上导航栏,工具栏的高度。假如用像素思考,容易使得做出的图片过大或者过小。假如是那种导航栏,工具栏之类的背景图,需要横跨整个屏幕。可以只切一小块,让程序拉伸,拉伸方式是保持两边的像素不动,只拉伸最中间的一列像素。需要拉伸的话,横方向就不要出现一些渐变色。