ios屏幕适配主要适配三个方面:Points,Pixels & PPI,SafeArea(留海屏),再加个:横竖屏
- iPhone尺寸
- Points
- Pixels & PPI
- SafeArea
iPhone尺寸
历年iPhone尺寸点这里
iOS Design Guidelines
Points
和web开发不同,native中尺寸是没有单位的,或者说只有默认的固定单位,iOS就是pt,Android就是dp,所以iOS布局就是对Points进行适配。
项目中UED不可能每款iPhone出一版视觉稿,例如只出iPhone6P的视觉稿,程序员需要根据用户实际机型进行尺寸缩放,即给代码中的尺寸数字乘以一个系数。
iPhone的宽度尺寸有三种:320,375,414。(就像web抛弃低版本IE一样,通常<iPhone6版本的320尺寸的可以放弃,只适配375,414两种尺寸)
// 是否为横屏的宏 #define IS_LANDSCAPE (UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation])) // 根据横屏竖屏取屏幕宽高 #define SCREEN_WIDTH (IS_LANDSCAPE ? [[UIScreen mainScreen] bounds].size.height : [[UIScreen mainScreen] bounds].size.width) #define SCREEN_HEIGHT (IS_LANDSCAPE ? [[UIScreen mainScreen] bounds].size.width : [[UIScreen mainScreen] bounds].size.height) // 根据屏幕尺寸进行缩放 static inline NSInteger UIAdapter (float x){ CGFloat scale = 414 / SCREEN_WIDTH; // 因为视觉稿是 iphone6P 是 414 宽度 return (NSInteger)x /scale; } static inline CGRect UIRectAdapter(x, y, width, height){ return CGRectMake(UIAdapter(x), UIAdapter(y), UIAdapter(width), UIAdapter(height)); } // 暴露给外部调用 #define UI(x) UIAdapter(x) #define UIRect(x,y,width,height) UIRectAdapter(x,y,width,height)
定义好逻辑分辨率(Point)的适配方法后,代码里就不要直接写数字了,改为调用上面的适配方法:
// 改前 self.sourceLabel.frame.size.width + 15, // 改后 self.sourceLabel.frame.size.width + UI(15), // 改前 self.commentLabel = [[UILabel alloc] initWithFrame:CGRect(100, 70, 50, 20)]; // 改后 self.commentLabel = [[UILabel alloc] initWithFrame:UIRect(100, 70, 50, 20)];
思路是:
- 根据 home 键的方向(iphone X 开始是虚拟 home 键)判断当前是横屏 / 竖屏
- 根据横屏 / 竖屏取屏幕宽高
- 缩放系数有两种方式:
- 方式一:UED视觉稿有统一标准的话(例如固定是 iphone6P)比较简单,如上【scale = 414 / SCREEN_WIDTH】即可
- 方式二:UED视觉稿机型可能会变的话,基准值可以通过参数传入
适配完,业务代码改造成:
// 原始代码,未经尺寸适配 self.sourceLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 15, 270, 50)]; self.sourceLabel.frame.size.width = 300; // 改造后的代码,经过尺寸适配 self.sourceLabel = [[UILabel alloc] initWithFrame:UIRect(20, 15, 270, 50)]; self.sourceLabel.frame.size.width = UI(300);
Pixels & PPI
Pixel就是在屏幕上的像素点。PPI(pixels-per-inch)即像素密度,屏幕对角线上像素点数 / 对角线长度,即像素密度,越高画面越清晰。
Apple从iPhone4开始推出了Retina视网膜屏,即2x两倍屏,相同单位尺寸下,能展示两倍的像素。从iPhone6P开始推出Retina HD视网膜屏,即3x三倍屏。
教主在iPhone4发布会上:
Point和Pixel的关系:
- non-retina : 1 point = 1 pixel
- Retina : 1 point = 2*2 pixels
- Retina HD: 1 point = 3*3 pixels
Pixel主要影响的是图片适配。UED用Sketch等工具会提供原始图片,@2x,@3x屏幕的图片
适配方案:
方案一:不适配,无脑用@3x的图片。@3x的图片在2x两倍屏上也能正常显示,只不过系统会进行压缩,消耗内存,而且@3x图片体积大浪费硬盘,但又不是你手机,Let it go~。但别无脑用@2x的图片,在3x屏幕上100 * 100的区域内,@2x的图片只能显示在66.6 * 66.6的区域,为了撑满100 * 100的显示区域,系统会将@2x的图片拉伸,会导致图片模糊,清晰度不够。
方案二:根据分辨率来适配
self.rightImageView.image = [UIScreen mainScreen].scale == 2 ? [UIImage imageNamed:@"icon.bundle/add@2x.png"] : [UIImage imageNamed:@"icon.bundle/add@3x.png"];
方案三:用 Assets.xcassets 自动适配图片,将 @2x,@3x 的图片拖到设备的相应方格中即可。
用 Assets.xcassets 的好处是,代码中不需要自己去判断分辨率了,也不用指定加@2x,@3x后缀,代码:
self.rightImageView.image = [UIImage imageNamed:@"add@2x.png"]
SafeArea
iPhoneX 推出全面屏,市面上开始普及留海,美人尖。留海会导致页面顶部区域被遮盖。底部虚拟 home 键的 home indictor 区域会响应上滑手势,虽然不像留海会遮挡页面显示,但有如进度条等滑动操作时会受影响。
适配方案就是预留出足够的顶部高度,避免遮盖,将顶部的 statusBar height:20 -> 44
另外别忘了适配横屏,横屏时页面左右两侧同样可能被留海遮盖,底部视频进度条同样可能被虚拟 home 键的 home indictor 区域遮盖,也需要留出来。
所以iPhoneX后的SafeArea如下。竖屏上右下左:{44 0 34 0},横屏上右下左:{0 44 21 44}
当然SafeArea是个指导概念,不是强制的,如果不影响显示和使用,不留白也行。或者像横屏视频进度条,只需要Y轴位置提高一点即可。
@implementation Screen + (CGSize)sizeFor58Inch { // iphonex return CGSizeMake(375, 812); } + (CGSize)sizeFor61Inch { // iphone xr return CGSizeMake(414, 896); } + (CGSize)sizeFor65Inch { // iphone xs max return CGSizeMake(414, 896); } @end
// 是否是 iphoneX / XR / XMAX #define IS_IPHONE_X (SCREEN_WIDTH == [Screen sizeFor58Inch].width && SCREEN_HEIGHT == [Screen sizeFor58Inch].height) #define IS_IPHONE_XR (SCREEN_WIDTH == [Screen sizeFor61Inch].width && SCREEN_HEIGHT == [Screen sizeFor61Inch].height && [UIScreen mainScreen].scale == 2) #define IS_IPHONE_XMAX (SCREEN_WIDTH == [Screen sizeFor65Inch].width && SCREEN_HEIGHT == [Screen sizeFor65Inch].height && [UIScreen mainScreen].scale == 3) // 这三种机型有留海屏 #define IS_IPHONE_X_XR_MAX (IS_IPHONE_X || IS_IPHONE_XR || IS_IPHONE_XMAX) // 如果是留海屏,调整 statusBar 高度 #define STATUSBAR_HEIGHT (IS_IPHONE_X_XR_MAX ? 44 : 20)
在IOS11中,UIScrollView,UICollectionView,UITableView已经自动适配了留海屏。
PS:对于AutoLayout的布局,系统同样提供了UILayoutGuide坐标体系。
PS:ReactNative里有SafeAreaView可以直接用