屏幕适配

7 9月

ios屏幕适配主要适配三个方面:基于Frame的大小位置适配,图片x2x3尺寸适配,iphoneX留海适配。

  • 逻辑分辨率(Point)
  • 物理分辨率,缩放因子
  • 留海屏

逻辑分辨率(Point)

布局都采用的逻辑分辨率进行适配。

逻辑分辨率(Point):就是屏幕的物理尺寸,从iphone5开始高度变高,iphone6开始宽度变宽。代码中写的,如左边距15,宽度20等都是逻辑分辨率。如果代码按小尺寸样式写,在大尺寸机型上会出现部分留白。解决方案就是按尺寸缩放,例如视觉稿统一是414宽的机型,代码中的尺寸值不做适配的话,在窄屏如iphone6上会错乱,需要在代码里的给尺寸值乘以一个系数。

通过UIScreen可以取到逻辑分辨率,如屏幕尺寸,亮度,坐标系等。通过UIDevice可以取到设备信息,如操作系统版本,横竖屏方向等。设备方向依据的就是home键的位置(UIDeviceOrientation)

// 是否为横屏的宏
#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)

// 方便外部调用
#define UI(x) UIAdapter(x)
#define UIRect(x,y,width,height) UIRectAdapter(x,y,width,height)

// 根据屏幕尺寸进行缩放
static inline NSInteger UIAdapter (float x){
    //方式一:分机型 特定的比例
    
    //方式二:屏幕宽度按比例适配
    CGFloat scale = 414 / SCREEN_WIDTH; //因为视觉稿是 iphoneXR 是 414 宽度
    return (NSInteger)x /scale;
}

static inline CGRect UIRectAdapter(x, y, width, height){
    return CGRectMake(UIAdapter(x), UIAdapter(y), UIAdapter(width), UIAdapter(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)];

物理分辨率,缩放因子

图片的适配需要使用物理分辨率,缩放因子用图片的@2x,@3x作为后缀区分。

物理分辨率即屏幕上肉眼看到的像素点里的实际像素个数。例如iphone3GS和iphone4的逻辑分辨率是完全一样的,都是320*480,但它俩的物理分辨率差了一倍。

iphone3Gs的逻辑分辨率和物理分辨率一样,都是320*480,缩放因子为@1x,表示1倍屏。

iphone4的逻辑分辨率是320*480,物理分辨率是640*960,缩放因子为@2x,表示2倍屏。

iphone6P的逻辑分辨率是414*736,物理分辨率是1080*1920,缩放因子为@3x,表示3倍屏。

如果懒得区分机型,可以无脑用@3x的图片,在非3倍屏上会被压缩,显示上是没问题的,但会造成内存的浪费。

图片在APP中可以存放在bundle里,或ImageAsset里。ImageAsset不用写图片@2x,@3x后缀,你需要在工程的Assets.xcassets里将@2x,@3x的图片拖进去就行,代码中使用也不需要写图片的@2x,@3x后缀,系统会自动选择合适的图片尺寸来显示。

留海屏

iphoneX开始推出了留海屏,顶部的statusBar高度从20变为44。做适配时顶部要让出留海的距离,底部要让出手势区域。

对于Frame的布局,系统提供了UIEdgeInsets安全区域,对于竖屏就是{44, 0, 34, 0},对于横屏就是{0, 44, 21, 44}

对于AutoLayout的布局,系统同样提供了UILayoutGuide坐标体系。

不用系统提供的,自己写点宏也很容易,就是让出些距离。

// iphone xs max
+ (CGSize)sizeFor65Inch {
    return CGSizeMake(414, 896);
}

// iphone xr
+ (CGSize)sizeFor61Inch {
    return CGSizeMake(414, 896);
}

// iphonex
+ (CGSize)sizeFor58Inch {
    return CGSizeMake(375, 812);
}

// 是否是 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 STATUSBARHEIGHT (IS_IPHONE_X_XR_MAX ? 44 : 20)

在IOS11中,UIScrollView,UICollectionView,UITableView已经自动适配了留海屏,你有可以将自动适配的关闭:

UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:flowlayout];
 
// 关闭系统为 UICollectionView 提供的自动适配留海屏功能
collectionView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;

发表评论

电子邮件地址不会被公开。 必填项已用*标注