当前位置:   article > 正文

IOS 屏幕适配(一)理论篇_ios ui适配

ios ui适配

1. IOS 屏幕适配基本概念


1.1 IOS 设备的尺寸和分辨率


1.1.1 分辨率相关概念

  • (Points):

是iOS开发中引入的抽象单位,称作点。开发过程中所有基于坐标系的绘制都是以 point 作为单位,在iPhone 2G,3G,3GS的年代,point 和屏幕上的像素是完全一一对应的,即 320 * 480 (points), 也是 320 * 480 (pixels)
  • 渲染像素 (Rendered Pixels):

Rendered Pixels: 渲染像素, 以 point 为单位的绘制最终都会渲染成 pixels,这个过程被称为光栅化。基于 point 的坐标系乘以比例因子可以得到基于像素的坐标系,高比例因子会使更多的细节展示,目前的比例因子会是 1x,2x,3x
  • 物理像素(Physical Pixels):

Physical Pixels: 物理像素,就是设备屏幕实际的像素
  • 设备屏幕的物理长度(Physical Device):

Physical Device: 设备屏幕的物理长度,使用英寸作为单位。比如iPhone 4屏幕是3.5英寸,iPhone 5 是4英寸,iphone 6是4.7英寸,这里的数字是指手机屏幕对角线的物理长度。实际上会是Physical Pixels的像素值(而不是Rendered Pixels的像素值)会渲染到该屏幕上, 屏幕会有 PPI(pixels-per-inch) 的特性,PPI 的值告诉你每英寸会有多少像素渲染。

1.1.2 IOS 各个设备对应的分辨率

机型

屏幕宽高(point)

渲染像素(pixel)

物理像素(pixel)

屏幕对角线长度(英寸)

屏幕模式

iPhone 2G,3G,3GS

320 * 480

320 * 480

320 * 480

3.5(163PPI)

1x

iPhone 4, 4s

320 * 480

640 * 960

640 * 960

3.5 (326PPI)

2x

iPhone 5, 5s

320 * 568

640 * 1136

640 * 1136

4 (326PPI)

2x

iPhone 6, 6s, 7

375 * 667

750 * 1334

750 * 1334

4.7 (326PPI)

2x

iPhone 6 Plus, 6s Plus, 7 Plus

414 * 736

1242 * 2208

1080 * 1920

5.5 (401PPI)

3x

  • iphone设备尺寸

机型

屏幕宽高(point)

比例

像素密度(PPI)

屏幕尺寸

型号代码

发布日

iPhone 2g

480×320

3:2

163ppi

3.5

iPhone1,1

2008.01

iPhone 3g

480×320

3:2

163ppi

3.5

iPhone1,2

2008.06

iPhone 3gs

480×320

3:2

163ppi

3.5

iPhone2,1

2009.06

iPhone 4

960×640

3:2

163ppi

3.5

iPhone3,1、iPhone3,2、iPhone3,3

2010.06

iPhone 4s

960×640

3:2

326ppi

3.5

iPhone4,1

2011.10

iPhone 5

1136×640

16:9

326ppi

4.0

iPhone5,1、iPhone5,2

2012.09

iPhone 5c

1136×640

16:9

326ppi

4.0

iPhone5,3、iPhone5,4

2013.09

iPhone 5s

1136×640

16:9

326ppi

4.0

iPhone6,1、iPhone6,2

2013.09

iPhone 6

1334×750

16:9

401ppi

4.7

iPhone7,2

2014.09

iPhone 6 plus

1920×1080

16:9

401ppi

5.5

iPhone7,1

2014.09

iPhone 6s

1334×750

16:9

401ppi

4.7

iPhone8,2

2015.09

iPhone 6s plus

1920×1080

16:9

401ppi

5.5

iPhone8,1

2015.09

iPhone 5 SE

1136×640

16:9

401ppi

4.0

iPhone8,4

2016.03

iPhone 7

1334×750

16:9

401ppi

4.7

iPhone9,1、iPhone9,3

2016.09

iPhone 7 plus

1920×1080

16:9

401ppi

5.5

iPhone9,2、iPhone9,4

2016.09

iPhone 8

1334×750

16:9

401ppi

4.7

iPhone10,1、iPhone10,4

2017.09

iPhone 8 plus

1920×1080

16:9

401ppi

5.5

iPhone10,2、iPhone10,5

2017.09

iPhone X

2436×1125

18:9

458ppi

5.8

iPhone10,3、iPhone10,6

2017.09

iPhone XS

2436×1125

18:9

458ppi

5.8

iPhone11,2

2018.09

iPhone XS Max

2688×1242

18:9

458ppi

6.5

iPhone11,4、iPhone11,6

2018.09

iPhone XR

1792×828

19.5:9

326ppi

6.1

iPhone11,8

2018.09

  • ipad 尺寸

机型

屏幕宽高(point)

屏幕模式(Scale)

物理像素(pixel)

比例

像素密度(PPI)

屏幕尺寸

型号代码

发布日

iPad

1024×768

@1x

1024×768

4:3

163ppi

9.7

iPad1,1

2010.01

iPad 2

1024×768

@1x

1024×768

4:3

163ppi

9.7

iPad2,1、iPad2,2、iPad2,3、iPad2,4

2011.03

iPad 3(New)

1024×768

@2x

2048×1536

4:3

264ppi

9.7

iPad3,1、iPad3,2、iPad3,3

2012.03

iPad 4

1024×768

@2x

2048×1536

4:3

264ppi

9.7

iPad3,4、iPad3,5、iPad3,6

2012.10

iPad 5

1024×768

@2x

2048×1536

4:3

264ppi

9.7

iPad6,11、iPad6,12

2017.03

  • ipad Air尺寸

机型

屏幕宽高(point)

屏幕模式(Scale)

物理像素(pixel)

比例

像素密度(PPI)

屏幕尺寸

型号代码

发布日

iPad Air

1024×768

@2x

2048×1536

4:3

264ppi

9.7

iPad4,1、iPad4,2、iPad4,3

2013.10

iPad Air 2

1024×768

@2x

2048×1536

4:3

264ppi

9.7

iPad5,3、iPad5,4

2014.10

  • iPad Pro 尺寸

机型

屏幕宽高(point)

屏幕模式(Scale)

物理像素(pixel)

比例

像素密度(PPI)

屏幕尺寸

型号代码

发布日

iPad Pro 12.9-inch

1366×1024

@2x

2732×2048

4:3

264ppi

12.9

iPad6,7、iPad6,8

2015.09

iPad Pro 9.7-inch

1024×768

@2x

2048×1536

4:3

264ppi

9.7

iPad6,3、iPad6,4

2016.03

iPad Pro 12.9-inch 2

1366×1024

@2x

2732×2048

4:3

264ppi

12.9

iPad7,1、iPad7,2

2017

iPad Pro 10.5

1112×834

@2x

2224×1668

4:3

264ppi

10.5

iPad7,3、iPad7,4

  • ipad Mini尺寸

机型

屏幕宽高(point)

屏幕模式(Scale)

物理像素(pixel)

比例

像素密度(PPI)

屏幕尺寸

型号代码

发布日

iPad mini

1024×768

@1X

1024×768

4:3

163

7.9

iPad2,5、iPad2,6、iPad2,7

2012.10

iPad mini 2

1024×768

@2X

2048×1536

4:3

326

7.9

iPad4,5、iPad4,6、iPad4,7

2013.10

iPad mini 3

1024×768

@2X

2048×1536

4:3

326

7.9

iPad4,7、iPad4,8、iPad4,9

2014.10

iPad mini 4

1024×768

@2X

2048×1536

4:3

326

7.9

iPad5,1、iPad5,2

2015.09

  • iPod Touch尺寸

机型

屏幕宽高(point)

屏幕模式(Scale)

物理像素(pixel)

比例

像素密度(PPI)

屏幕尺寸

型号代码

发布日

iTouch

480*320

@1X

480*320

3:2

163ppi

3.5

iPod1,1

2007.09

iTouch 2

480*320

@1X

480*320

3:2

163ppi

3.5

iPod2,1

2008.09

iTouch 3

480*320

@1X

480*320

3:2

163ppi

3.5

iPod3,1

2009.09

iTouch 4

480*320

@2X

960*640

3:2

326ppi

3.5

iPod4,1

2010.09

iTouch 5

568*320

@2X

1136*640

16:9

326ppi

4.0

iPod5,1

2012.09

iTouch 6

568*320

@2X

1136*640

16:9

326ppi

4.0

iPod7,1

2015.07

  • 1x, 2x, 3x 的含义:

屏幕模式,描述的就是屏幕中一个点有多少个 Rendered Pixels 渲染,对于2倍屏(又称 Retina 显示屏),会有 2 * 2 = 4 个像素的面积渲染,对于3倍屏(又称 Retina HD 显示屏),会有 3 * 3 = 9 个像素的面积渲染。
iOS 开发中,所有控件的坐标以及控件大小都是以点为单位的,假如我在屏幕上需要展示一张 20 * 20 (单位:point)大小的图片,那么设计师应该怎么给我图呢?这里就会用到屏幕模式的概念,如果屏幕是 2x,那么就需要提供 40 * 40 (单位: pixel)大小的图片,如果屏幕是 3x,那么就提供 60 * 60 大小的图片,且图片的命名需要遵守以下规范: Standard:<device_modifier>.<filename_extension> High resolution:@2x<device_modifier>.<filename_extension> High HD resolution:@3x<device_modifier>.<filename_extension>
ImageName: 图片名字,根据场景命名 device_modifier: 可选,可以是 ~ipad 或者 ~iphone, 当需要为 iPad 和 iPhone 分别指定一套图时需要加上此字段 filename_extension: 图片后缀名,iOS中使用 png 图片
例如: MyImage.png - 1x 显示屏自动加载的图片版本 MyImage@2x.png - 2x 显示屏自动加载的图片版本 MyImage@3x.png - 3x 显示屏自动加载的图片版本 MyImage@2x~iphone.png - 2x iPhone 和 iPod touch 显示屏自动加载的图片版本 MyImage@3x~iphone.png - 3x iPhone and iPod 显示屏自动加载的图片版本
  • 2x屏幕的设备会自动加载 xxx@2x.png 命名的图片资源,3x屏幕的设备会自动加载 xxx@3x.png 的图片, 现在基本没有 1x屏幕的设备了,可以不用提供这个分辨率的图片了。

1.2 设计和开发之间的多屏适配问题


  • 现在APP设计开发必须考虑适配大、中、小三种屏幕。所以如何做到交付一套设计稿解决适配大中小三屏的问题?设计和开发之间采用什么协作模式?

一个基本思路是:
选择一种尺寸作为设计和开发基准;
定义一套适配规则,自动适配剩下两种尺寸;
特殊适配效果给出设计效果。

更多详情可以参考这篇文章:手机淘宝的设计方案

  • 参考手机淘宝的设计方案如下:

第一步,视觉设计阶段,设计师按宽度750px(iPhone 6)做设计稿,除图片外所有设计元素用矢量路径来做。设计定稿后在750px的设计稿上做标注,输出标注图。同时等比放大1.5倍生成宽度1125px的设计稿,在1125px的稿子里切图。
第二步,输出两个交付物给开发工程师:一个是程序用到的@3x切图资源,另一个是宽度750px的设计标注图。
第三步,开发工程师拿到750px标注图和@3x切图资源,完成iPhone 6(375pt)的界面开发。此阶段不能用固定宽度的方式开发界面,得用自动布局(auto layout),方便后续适配到其它尺寸。
第四步,适配调试阶段,基于iPhone 6的界面效果,分别向上向下调试iPhone 6 plus(414pt)和iPhone 5S及以下(320pt)的界面效果。由此完成大中小三屏适配。
  • 为什么选择iPhone 6作为基准尺寸?

当面对大中小三种屏幕需要适配的时候,很容易想到先做好一种屏幕,再去适配剩下两种屏幕。第一个决定是到底以哪种屏幕作为设计和开发的基准尺寸。我们选择中间尺寸的iPhone 6(750px/375pt)作为基准,基于几个原因:
从中间尺寸向上和向下适配的时候界面调整的幅度最小。375pt下的设计效果适配到414pt和320pt偏差不会太大。假设以414pt为基准做出很优雅的设计,到320pt可能元素之间比例就不是那么回事了,比如图片和文字之间视觉比例可能失调。
iPhone 6 plus有两种显示模式,标准模式分辨率为1242x2208,放大模式分辨率为1125x2001(即iPhone 6的1.5倍)。可见官方系统里iPhone 6和iPhone 6 plus分辨率之间就存在1.5倍的倍率关系。很多情况下这两种尺寸可以用1.5倍直接等比适配。
1242x2208这个奇葩的数值是苹果官方都不愿意公开宣传的一个分辨率,不便于记忆和计算栅格。640x1136虽然是广泛应用的一个分辨率,但是大屏时代依然以小尺寸为设计基准显然不合时宜,设计师会停留在小屏的视角做设计. 所以,iPhone6的750x1334是最适合基准尺寸

1.3 开发时适配规范


  • 适配规则

:文字流式,控件弹性,图片等比缩放。

控件弹性指的是,navigation、cell、bar等适配过程中垂直方向上高度不变;水平方向宽度变化时,通过调整元素间距或元素右对齐的方式实现自适应。这样屏幕越大,在垂直方向上可以显示更多内容,发挥大屏幕的优势。

2. IOS 屏幕适配代码实现


2.1 布局处理


2.1.1 masonary布局适配实例

  • 在使用masonary自动布局时,可以根据6s的屏幕设计,设置一个比例系数,比如

//以6/6s为准宽度缩小系数

#define kJLXWidthScale [UIScreen mainScreen].bounds.size.height/375.0

复制代码

//高度缩小系数

#define kJLXHeightScale [UIScreen mainScreen].bounds.size.height/667.0

复制代码

  • 这样在布局的的时候,可以考虑使用上这个系数设置高度

UIButton *createrButton = [[UIButton alloc] init];

[self.view addSubview:createrButton];

UIEdgeInsets padding = UIEdgeInsetsMake(0, 10, 65, 10);

[createrButton setBackgroundImage:[UIImage imageNamed:@"common_button_pink"] forState:UIControlStateNormal];

[createrButton mas_makeConstraints:^(MASConstraintMaker *make){

make.left.equalTo(self.view.mas_left).with.offset(padding.left);

make.height.equalTo(@(60*kJLXHeightScale));

make.bottom.equalTo(self.view.mas_bottom).with.offset(-padding.bottom);

make.right.equalTo(self.view.mas_right).with.offset(-padding.right);

}];

复制代码

  • 这样在5s小屏手机上面,按钮的高度就会根据比例系数来动态调整大小。

2.1.2 Jimu 1.0 用到的布局适配函数

  • 之前Jimu 1.0中用到的布局转换主要通过下面这个函数来转换实际的宽度或高度:

横屏下,水平方向适配函数

/// 设备横屏下,水平方向适配·

///

/// - Parameters:

/// - iPhone6Scale: iPhone6 水平方向@2x尺寸

/// - iPadScale: 分辨率比例为768*1024的iPad 水平方向@2x尺寸

/// - Returns: 适配后的尺寸

func layoutHorizontal(iPhone6 iPhone6Scale: Float, iPad iPadScale: Float) -> Float {

let iphoneWidth = iPhone6Scale / 2

let iPadWidth = iPadScale / 2

var newWidth: Float = 0

switch Device.type() {

case .iPhone4:

newWidth = iphoneWidth * (480.0 / 667.0)

case .iPhone5:

newWidth = iphoneWidth * (568.0 / 667.0)

case .iPhone6:

newWidth = iphoneWidth

case .iPhone6p:

newWidth = iphoneWidth * (736.0 / 667.0)

case .iPhoneX:

newWidth = iphoneWidth * ((812.0 - 78) / 667.0)

case .iPhoneXR:

newWidth = iphoneWidth * ((896.0 - 78) / 667.0)

case .iPad_768_1024:

newWidth = iPadWidth

case .iPad_834_1112:

newWidth = iPadWidth * (1112.0 / 1024.0)

case .iPad_1024_1366:

newWidth = iPadWidth * (1366.0 / 1024.0)

}

return newWidth

}

复制代码

设备横屏下,垂直方向适配函数

/// 设备横屏下,垂直方向适配

///

/// - Parameters:

/// - iPhone6Scale: iPhone6 垂直方向@2x尺寸

/// - iPadScale: 分辨率比例为768*1024的iPad 垂直方向@2x尺寸

/// - Returns: 适配后的尺寸

func layoutVertical(iPhone6 iPhone6Scale: Float, iPad iPadScale: Float) -> Float {

let iphoneHeight = iPhone6Scale / 2

let iPadHeight = iPadScale / 2

var newHeight: Float = 0

switch Device.type() {

case .iPhone4:

newHeight = iphoneHeight * (320.0 / 375.0)

case .iPhone5:

newHeight = iphoneHeight * (320.0 / 375.0)

case .iPhone6:

newHeight = iphoneHeight

case .iPhone6p:

newHeight = iphoneHeight * (414.0 / 375.0)

case .iPhoneX:

newHeight = iphoneHeight * (375.0 / 375.0)

case .iPhoneXR:

newHeight = iphoneHeight * (414.0 / 375.0)

case .iPad_768_1024:

newHeight = iPadHeight

case .iPad_834_1112:

newHeight = iPadHeight * (834.0 / 768.0)

case .iPad_1024_1366:

newHeight = iPadHeight * (1024.0 / 768.0)

}

return newHeight

}

复制代码

  • 这种适配方式,可以满足横屏下适配各种设备,但是所有布局的代码都需要调用这两个函数,浸入性很强。所以需要优化一下。

2.1.3 布局适配优化

2.1.3.1 增加判断设备类型的extension扩展
  • 先来看一下之前Jimu 1.0 是通过一个自定义枚举来实现的,这样的不好的地方也是浸入性很强,每个调用的地方都需要用这个枚举值

/// 获取设备型号

enumDevice{

caseiPhone4 /// 4/4s 320*480 @2x

caseiPhone5 /// 5/5C/5S/SE 320*568 @2x

caseiPhone6 /// 6/6S/7/8 375*667 @2x

caseiPhone6p /// 6P/6SP/7P/8P 414*736 @3x

caseiPhoneX /// X 375*812 @3x

// case iPhoneXS /// XS 375*812 @3x (同X)

caseiPhoneXR /// XR 414*896 @2x (放大模式下为 375*812)

// case iPhoneXSMAX /// XSMAX 414*896 @3x (同XR)

caseiPad_768_1024 /// iPad(5th generation)/iPad Air/iPad Air2/iPad pro(9.7) 768*1024 @2x

caseiPad_834_1112 /// iPad pro(10.5) 834*1112 @2x

caseiPad_1024_1366 /// iPad pro(12.9) 1024*1366 @2x

/// 判断具体设备

///

/// - Returns: 具体设备名

staticfunctype()->Device{

switchscreenWidth{

case480.0:

return.iPhone4

case568.0:

return.iPhone5

case667.0:

return.iPhone6

case736.0:

return.iPhone6p

case812.0:

return.iPhoneX

case896.0:

return.iPhoneXR

case1024.0:

return.iPad_768_1024

case1112.0:

return.iPad_834_1112

case1366.0:

return.iPad_1024_1366

default:

return.iPad_768_1024

}

}

/// 判断是否为iPad

///

/// - Returns: true 是, false 否

staticfuncisIPad()->Bool {

// print("() = \(self.type())")

return(UI_USER_INTERFACE_IDIOM()==UIUserInterfaceIdiom.pad)

}

staticfuncisIPhone5()->Bool{

returnDevice.type()==Device.iPhone5?true:false

}

staticvarsafeAreaInsets:UIEdgeInsets{

if#available(iOS11.0,*){

returnUIApplication.shared.delegate?.window??.safeAreaInsets??.zero

}

return.zero

}

staticvarsafeScreenWidth:CGFloat{

returnUIScreen.main.bounds.width-safeAreaInsets.left-safeAreaInsets.right

}

staticvarsafeScreenHeight:CGFloat{

returnUIScreen.main.bounds.height-safeAreaInsets.top-safeAreaInsets.bottom

}

}

复制代码

  • 将上面设备类型判断代码优化为UIDevice的一个类扩展

extensionUIDevice {

funcVersion()->String{

letappVersion: String=Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as!String

returnappVersion

}

@objcpublicclassfuncisiPhoneX() ->Bool {

if (UIScreen.main.currentMode?.size.equalTo(CGSize.init(width: 1125, height: 2436)))! {

returntrue

}

returnfalse

}

publicclassfuncisiPhone6PlusBigMode() ->Bool {

if (UIScreen.main.currentMode?.size.equalTo(CGSize.init(width: 1125, height: 2001)))! {

returntrue

}

returnfalse

}

publicclassfuncisiPhone6Plus() ->Bool {

if (UIScreen.main.currentMode?.size.equalTo(CGSize.init(width:1242, height: 2208)))! {

returntrue

}

returnfalse

}

publicclassfuncisiPhone6BigMode() ->Bool{

if (UIScreen.main.currentMode?.size.equalTo(CGSize.init(width: 320, height: 568)))! {

returntrue

}

returnfalse

}

publicclassfuncisiPhone6() ->Bool {

if (UIScreen.main.currentMode?.size.equalTo(CGSize.init(width:750, height: 1334)))! {

returntrue

}

returnfalse

}

publicclassfuncisiPhone5() ->Bool {

if (UIScreen.main.currentMode?.size.equalTo(CGSize.init(width: 640, height: 1136)))! {

returntrue

}

returnfalse

}

publicclassfuncisiOS11() ->Bool {

if#available(iOS11.0, *) {

returntrue

} else {

returnfalse

}

}

publicclassfuncisiOS10() ->Bool {

if#available(iOS10.0, *) {

returntrue

} else {

returnfalse

}

}

publicclassfuncisiOS9() ->Bool {

if#available(iOS9.0, *) {

returntrue

} else {

returnfalse

}

}

publicclassfuncisiOS8() ->Bool {

if#available(iOS8.0, *) {

returntrue

} else {

returnfalse

}

}

publicclassfuncisAiPad() ->Bool {

ifUIDevice.current.userInterfaceIdiom==UIUserInterfaceIdiom.pad {

returntrue

}

returnfalse

}

}

复制代码

  • 然后为了简化调用,可以定义一个全局变量

// MARK: - 判断 机型

let isiPhone5 = UIDevice.isiPhone5()

let isiPhone6 = UIDevice.isiPhone6()

let isiPhone6BigModel = UIDevice.isiPhone6BigMode()

let isiPhone6Plus = UIDevice.isiPhone6Plus()

let isiPhone6PlusBigMode = UIDevice.isiPhone6PlusBigMode()

let isiPhoneX = UIDevice.isiPhoneX()

let isIpad = UIDevice.isAiPad()

// MARK: - 系统类型

let kisiOS11 = UIDevice.isiOS11()

let kisiOS10 = UIDevice.isiOS10()

let kisiOS9 = UIDevice.isiOS9()

let kisiOS8 = UIDevice.isiOS8()

复制代码

  • 定义全局变量简化屏幕宽度,高度计算

letscreenWidth=max(UIScreen.main.bounds.height,UIScreen.main.bounds.width)

letscreenHeight=min(UIScreen.main.bounds.height,UIScreen.main.bounds.width)

letscreenBounds=UIScreen.main.bounds

复制代码

2.1.3.2 增加 NSInteger 类扩展

extensionNSInteger{

/// iphone 5 上的大小

///

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/269368
推荐阅读
相关标签