1.iPhone尺寸规格
2.屏幕尺寸
-
1 inch = 2.54cm = 25.4mm; 上表中的宽高(width/height)为手机的物理尺寸,包括显示屏和边框。我们通常所说的iPhone5屏幕尺寸为4英寸、iPhone6屏幕尺寸为4.7英寸,指的是显示屏对角线的长度(diagonal)。
3.像素密度PPI
-
PPI(Pixel Per Inch by diagonal):表示沿着对角线,每英寸所拥有的像素(Pixel)数目。PPI数值越高,代表显示屏能够以越高的密度显示图像,即通常所说的分辨率越高、颗粒感越弱。
根据勾股定理,可以得知iPhone4(s)的PPI计算公式为:
4.缩放因子(scale factor between logic point and device pixel)
(1)Scale起源
早期的iPhone3GS的屏幕分辨率是320480(PPI=163),iOS绘制图形(CGPoint/CGSize/CGRect)均以point为单位(measured in points): 1 point = 1 pixel(Point Per Inch=Pixel Per Inch=PPI)
后来在iPhone4中,同样大小(3.5 inch)的屏幕采用了Retina显示技术,横、纵向方向像素密度都被放大到2倍,像素分辨率提高到(320x2)x(480x2)= 960x640(PPI=326), 显像分辨率提升至iPhone3GS的4倍(1个Point被渲染成1个2x2的像素矩阵)
但是对于开发者来说,iOS绘制图形的API依然沿袭point(pt,注意区分印刷行业的“磅”)为单位。在同样的逻辑坐标系下(320x480):
1 point = scalepixel(在iPhone4~6中,缩放因子scale=2;在iPhone6+中,缩放因子scale=3)。
可以理解为:scale=绝对长度比(point/pixel)= 单位长度内的数量比(pixel/point)
(2)UIScreen.scale
UIScreen.h中定义了该属性:
// The natural scale factor associated with the screen.(read-only)
@property(nonatomic,readonly) CGFloat scale NS_AVAILABLE_IOS(4_0);
//This value reflects the scale factor needed to convert from the default logical coordinate space into the device coordinate space of this screen. //The default logical coordinate space is measured using points. For standard-resolution displays, the scale factor is 1.0 and one point equals one pixel. For Retina displays, the scale factor is 2.0 and one point is represented by four pixels.
为了自动适应分辨率,系统会根据设备实际分辨率,自动给UIScreen.scale赋值,该属性对开发者只读。
iOS8新增了nativeScale属性,初步看来nativeScale与scale没有太大区别:
// Native scale factor of the physical screen
@property(nonatomic,readonly) CGFloat nativeScale NS_AVAILABLE_IOS(8_0);
5.@2x/@3x以及高倍图适配
(1)@2x
@2x means the same “double”retina resolution that we’veseen on all iOS devices with retina displays to date, where each virtual pointin the user interface is represented by two physical pixels on thedisplay in each dimension, horizontal and vertical.
iPhone3GS时代,我们为一个应用提供图标(或按钮提供贴图),只需要icon.png。针对现在的iPhone4~6 Retina显示屏,需要制作额外的@2x高分辨率版本。
例如在iPhone3GS中,scale=1,用的图标是50x50pixel(logicalimage.size=50x50point);在iPhone4~6中,scale=2,则需要100×100pixel(logical image.size=50x50point,乘以image.scale=dimensions in pixels),并且命名为icon@2x.png。
如果APP要同时兼容iPhone3GS~iPhone6,则需要提供icon.png/icon@2x.png两种分辨率的图片。
(2)@3x
@3x means a new “triple” retina resolution, where eachuser interface point is represented by three display pixels. A single @2x pointis a 2 × 2 square of 4 pixels; an @3x point is a 3 × 3 square of 9 pixels.”
iPhone6+在实际渲染时,downsampling/1.15(1242x2208->1080x1920),准确的讲,应该是@2.46x。苹果为方便开发者用的是@3x的素材,然后再缩放到@2.46x上。
参考:[《为什么iPhone 6 Plus要将3x渲染的2208x1242分辨率缩小到1080p屏幕上?》](https://www.zhihu.com/question/25288571 “为什么iPhone 6 Plus要将3x渲染的2208x1242分辨率缩小到1080p屏幕上?”) 《iPhone 6 Plus屏幕分辨率》
需要注意的是,iOS APP图标的尺寸和命名都需要遵守相关规范。
(3)高倍图文件命名
对于iPhone3、4/5/6、6+三类机型,需要按分辨率提供相应的高倍图并且文件名添加相应后缀,否则会拉伸(stretchable/resizable)失真(模糊或边角出现锯齿)。
-
以下基于UIImage的两类初始化API简介高倍图的适配:
- <1>+imageNamed:该方法使用系统缓存,适合表视图重复加载图像的情形。同时该API根据UIScreen的scale,自动查找包含对应高倍图后缀名(@2x)的文件,如果找到二倍图,则image.scale=2.0,对应逻辑size大小以point度量(pixel度量的一半);如果没找到设置默认image.scale=1.0,对应逻辑size大小同像素尺寸。因此,使用该方法,无需特意指定高倍图后缀。在实际运行时,系统如果发现当前设备是Retina屏(scale=2),会自动寻找"*@2x.png"命名格式的图片,加载针对Retina屏的图片素材,否则会失真。
<2>+imageWithContentsOfFile/+imageWithData:(scale:)/-initWithContentsOfFile:/-initWithData:(scale:)
这组方法创建的UIImage对象没有使用系统缓存,并且指定文件名必须包含明确的高倍图后缀。如果文件名包含@2x后缀,则image.scale=2.0;否则默认image.scale=1.0,同样对于Retina屏将会失真。<3>目前,适配iPhone6+时,除了一些铺满全屏的大图(LogoIcon、LaunchImage)需提供三倍图,其他的小图仍可沿用原有的二倍图自适应拉伸。
6.Screen Bounds & Application Frame
(1)UIScreen.bounds
// Bounds of entire screen in points(本地坐标系,起点为[0,0])
@property(nonatomic,readonly) CGRect bounds;
--------------------------------------------------------------------------------
//考虑转屏的影响,按照实际屏幕方向(UIDeviceOrientation)的宽高
#define SCREEN_WIDTH ([UIScreen mainScreen].bounds.size.width)
#define SCREEN_HEIGHT ([UIScreen mainScreen].bounds.size.height)
#define STATUSBAR_HEIGHT ([UIApplication sharedApplication].statusBarFrame.size.height)
//不考虑转屏的影响,只取竖屏(UIDeviceOrientationPortrait)的宽高
#define SCREEN_WIDTH MIN([UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height)
#define SCREEN_HEIGHT MAX([UIScreen mainScreen].bounds.size.height, [UIScreen mainScreen].bounds.size.width)
#define STATUSBAR_HEIGHT MIN([UIApplication sharedApplication].statusBarFrame.size.width, [UIApplication sharedApplication].statusBarFrame.size.height)
(3)UIScreen.applicationFrame
// Frame of application screen area in points (i.e.entire screen minus status bar if visible)
// bounds除去系统状态栏
@property(nonatomic,readonly) CGRect applicationFrame;
--------------------------------------------------------------------------------
// APPFRAME_WIDTH=SCREEN_WIDTH
#define APPFRAME_WIDTH ([UIScreen mainScreen].applicationFrame.size.width)
// APPFRAME_HEIGHT=SCREEN_HEIGHT-STATUSBAR_HEIGHT
//注意:横屏(UIDeviceOrientationLandscape)时,iOS8默认隐藏状态栏,此时APPFRAME_HEIGHT=SCREEN_HEIGHT
#define APPFRAME_HEIGHT ([UIScreen mainScreen].applicationFrame.size.height)
--------------------------------------------------------------------------------
(4)bounds和frame的区别:
bounds的原点是(0,0)点(就是view本身的坐标系统,默认永远都是0,0点,除非认为setbounds),而frame的原点却是任意的(相对于父视图中的坐标位置)。
如图所示:
- frame: 该view在父view坐标系统中的位置和大小。相对于父视图而言(参照点是,父类的坐标系统)
- bounds:该view在自身的坐标系统中的位置和大小。相对于自身视图而言(参照点是,自身的坐标系统,就相当于View B自己的坐标系统,以0,0点为起点)
- center:该view的中心点在父view坐标系统中的位置和大小。(参照点是,父类的坐标系统)