IOS開發之尺寸

  在移動端或者前端開發中,UI圖一般是帶標註的,指定某個控件的長寬等屬性,通常UI給的是68px,72px這樣的樣式,可是咱們在開發過程當中一般又並非徹底按照上面的標註去設置值,有時候須要將這個標註除以2或者除以3在進行賦值給frame,這其中的緣由是由於標註通常都是按px格式給的,可是iOS底層繪製的時候是按照pt爲單位進行繪製,這兩個的區別在於:html

  • px就是表示pixel,像素,是屏幕上顯示數據的最基本的點。px是一個點,它不是天然界的長度單位,誰能說出一個「點」有多長多大麼?能夠畫的很小,也能夠很大。若是點很小,那畫面就清晰,咱們稱它爲「分辨率高」,反之,就是「分辨率低」。因此,「點」的大小是會「變」的,也稱爲「相對長度」。
  • pt就是point,是印刷行業經常使用單位,等於1/72英寸。pt全稱爲point,但中文不叫「點」,查金山詞霸能夠看到,確切的說法是一個專用的印刷單位「磅」,大小爲1/72英寸。因此它是一個天然界標準的長度單位,也稱爲「絕對長度」。

  

在瀏覽網頁過程當中,全部的「大」「小」概念,都是基於「屏幕」這個「界面」上。「屏幕」上的各類信息,包括文字、圖片、表格等等,都會隨屏幕的分辨率變化而變化,一個100px寬度大小的圖片,在800×600分辨率下,要佔屏幕寬度的1/8,但在1024×768下,則只佔約1/10。因此若是在定義字體大小時,使用px做爲單位,那一旦用戶改變顯示器分辨率從800到1024,用戶實際看到的文字就要變「小」(天然長度單位),甚至會看不清,影響瀏覽。前端

  那是否是用pt作單位就沒這樣的問題呢?錯!問題一樣出現。剛纔的例子已經很清楚的說明,在不一樣分辨率下,不管是px仍是pt,都會改變大小。以如今的電腦屏幕狀況,尚未一種單位能夠保證,在不一樣分辨率下,一個文字大小能夠「固定不變」。由於這很難以實現也不是頗有必要:全球電腦用戶以億來數,屏幕從14寸到40寸甚至更高都有,屏幕大小不一樣,分辨率也不一樣,要保證一個字體在全部用戶面前大小同樣,實在是MISSION IMPOSSIBLE。ios

  目前iOS的手機屏幕的分辨率隨着機型的變化樣一直在變化,那麼咱們在作開發時要如何作好適配呢?這就須要咱們瞭解更多的關於iOS開發過程當中的尺寸相關的一些知識了。git

1.iPhone尺寸規格

   1 inch = 2.54cm = 25.4mmgithub

手機編程

尺寸緩存

邏輯分辨率(pt)app

像素分辨率(px)iphone

Scale factoride

PPI

3GS

3.5-inch

320 x 480

320 x 480

@1x

163

iPhone 4

3.5-inch

320 x 480

640 x 960

@2x

326

iPhone 5/5S/5C/SE

4.0-inch

320 x 568

640 x 1136

@2x

326

iPhone 6/7/8 Plus

5.5-inch

414 x 736

1080 x 1920

@3x

401

iPhone 6/6S/7/8

4.7-inch

375 x 667

750 x 1334

@2x

326

iPhone X/XS

5.8-inch

375 x 812

1125 x 2436

@3x

458

iPhone XR

6.1-inch

414 x 896

828 x 1792

@2x

326

iPhone XR Max

6.5-inch

414 x 896

1242 x 2688

@3x

458

2.iPhone手機寬高

    上表中的寬高(width/height)爲手機的物理尺寸,包括顯示屏和邊框。如下爲iPhone4s的寬高示意圖:

3.屏幕尺寸

    咱們一般所說的iPhone5屏幕尺寸爲4英寸、iPhone6屏幕尺寸爲4.7英寸,指的是顯示屏對角線的長度(diagonal)。如下爲iPhone5~6+的屏幕尺寸規格示意圖:

4.像素密度PPI

    PPI(Pixel Per Inch by diagonal):表示沿着對角線,每英寸所擁有的像素(Pixel)數目。PPI數值越高,表明顯示屏可以以越高的密度顯示圖像,即一般所說的分辨率越高、顆粒感越弱。

    根據勾股定理,能夠得知iPhone4(s)的PPI計算公式爲:

    計算結果稍有出入,這是由於像素的離散採樣有鋸齒效應。

5.縮放因子(scale factor between logic point and device pixel)

(1)Scale起源

    早期的iPhone3GS的屏幕分辨率是320*480(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 = scale*pixel(在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賦值,該屬性對開發者只讀。

(3)UIScreen.nativeScale

    iOS8新增了nativeScale屬性:

// Native scale factor of the physical screen
@property(nonatomic,readonly) CGFloat nativeScale NS_AVAILABLE_IOS(8_0);

    如下是iPhone6+下的輸出,初步看來nativeScale與scale沒有太大區別

(lldb)p (CGFloat)[[UIScreen mainScreen] scale]
(CGFloat) $1 = 3
(lldb) p(CGFloat)[[UIScreen mainScreen] nativeScale]
(CGFloat) $2 = 3

(4)機型判別

    在一樣的邏輯分辨率下,能夠經過scale參數識別是iPhone3GS仍是iPhone4(s)。如下基於nativeScale參數,定義了探測機型是否爲iPhone6+的宏:

// not UIUserInterfaceIdiomPad
#define IS_IPHONE (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
// detect iPhone6 Plus based on its native scale
#define IS_IPHONE_6PLUS (IS_IPHONE && [[UIScreenmainScreen] nativeScale] == 3.0f)

    那麼,一樣的分辨率和scale,如何區分機型iPhone4與4s、iPhone5與5s呢?經過[[UIDevice currentDevice] model]只能判別iPhone、iPad、iPod大類,要判斷iPhone具體機型型號,則須要經過sysctlbyname("hw.machine")獲取詳細的設備參數信息予以甄別。

6.Resolutions & Rendering

7.@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屏幕上?》《詳解 iPhone 6 Plus 的奇葩分辨率》《iPhone 6 Plus屏幕分辨率

    若是APP要同時兼容iPhone3GS~iPhone6+,則須要提供icon.png/icon@2x.png/icon@3x.png三種分辨率的圖片。

    須要注意的是,iOS APP圖標的尺寸命名都須要遵照相關規範。

(3)高倍圖文件命名

    對於iPhone三、4/5/六、6+三類機型,須要按分辨率提供相應的高倍圖而且文件名添加相應後綴,不然會拉伸(stretchable/resizable)失真(模糊或邊角出現鋸齒)。
    如下基於UIImage的兩類初始化API簡介高倍圖的適配:

  • +imageNamed:該方法使用系統緩存,適合表視圖重複加載圖像的情形。同時該API根據UIScreen的scale,自動查找包含對應高倍圖後綴名(@2x)的文件,若是找到二倍圖,則image.scale=2.0,對應邏輯size大小以point度量(pixel度量的一半);若是沒找到設置默認image.scale=1.0,對應邏輯size大小同像素尺寸。所以,使用該方法,無需特地指定高倍圖後綴。在實際運行時,系統若是發現當前設備是Retina屏(scale=2),會自動尋找"*@2x.png"命名格式的圖片,加載針對Retina屏的圖片素材,不然會失真。
  • +imageWithContentsOfFile/+imageWithData:(scale:)/-initWithContentsOfFile:/-initWithData:(scale:)這組方法建立的UIImage對象沒有使用系統緩存,而且指定文件名必須包含明確的高倍圖後綴。若是文件名包含@2x後綴,則image.scale=2.0;不然默認image.scale=1.0,一樣對於Retina屏將會失真。
  • 目前,適配iPhone6+時,除了一些鋪滿全屏的大圖(LogoIcon、LaunchImage)需提供三倍圖,其餘的小圖仍可沿用原有的二倍圖自適應拉伸。

8.Screen Bounds & Application Frame

(1)UIScreen.bounds

// Bounds of entire screen in points(本地座標系,起點爲[0,0])
@property(nonatomic,readonly) CGRect bounds; 

--------------------------------------------------------------------------------
//考慮轉屏的影響,按照實際屏幕方向(UIDeviceOrientation)的寬高
#define SCREEN_WIDTH ([UIScreenmainScreen].bounds.size.width)
#define SCREEN_HEIGHT ([UIScreenmainScreen].bounds.size.height)
#define STATUSBAR_HEIGHT ([UIApplicationsharedApplication].statusBarFrame.size.height)

//不考慮轉屏的影響,只取豎屏(UIDeviceOrientationPortrait)的寬高
#define SCREEN_WIDTH MIN([UIScreenmainScreen].bounds.size.width, [UIScreenmainScreen].bounds.size.height)
#define SCREEN_HEIGHT MAX([UIScreenmainScreen].bounds.size.height, [UIScreenmainScreen].bounds.size.width)
#define STATUSBAR_HEIGHT MIN([UIApplicationsharedApplication].statusBarFrame.size.width, [UIApplicationsharedApplication].statusBarFrame.size.height)
--------------------------------------------------------------------------------

(2)UIScreen.nativeBounds

    iOS8新增了nativeBounds屬性,輸出豎屏像素級分辨率:

// The bounding rectangle of the physical screen,measured in pixels. (read-only)
// This rectangle is based on the device in a portrait-up orientation. This value does not change as the device rotates.
@property(nonatomic,readonly) CGRect nativeBounds NS_AVAILABLE_IOS(8_0);

//如下是iPhone6+下的輸出:
--------------------------------------------------------------------------------
(lldb) poNSStringFromCGRect([(UIScreen*)[UIScreen mainScreen] bounds])
{{0, 0}, {414, 736}}
(lldb) poNSStringFromCGRect([(UIScreen*)[UIScreen mainScreen] nativeBounds])
{{0, 0}, {1242, 2208}}
--------------------------------------------------------------------------------

(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和frame的區別

 

9.機型尺寸適配(Screen Scale Adaption)

    從iPhone3GS/iPhone4(s)過渡到iPhone5(s)時,在邏輯上寬度不變高度稍高,以前舊的素材和佈局經過AutoresizingFlexible簡單適配便可運行得很好,但因爲高寬比增大,上下兩端出現黑粗邊(典型如LaunchImage)。從分辨率的角度來看,除了須要提供LaunchImage這種滿屏圖,其餘基本沿用二倍圖(@2x);從屏幕尺寸角度來看,須要對縱向排版略加調整。

    從iPhone5(s)發展到iPhone6(+),因爲高寬比保持不變,iOS對圖標、圖片、字體進行等比放大自適應,清晰度會有所下降。同時,絕對座標佈局會致使在大屏下出現偏左偏上的問題。從分辨率的角度來看,iPhone6沿用二倍圖(@2x),但需爲iPhone6+提供更高的三倍圖(@3x);從屏幕尺寸角度來看,須要從新對UI元素尺寸和佈局進行適配,以期視覺協調。

(1)按寬度適配

    咱們先來看一下iPhone4~6(+)的屏幕高寬比:

  • iPhone4(s):分辨率960*640,高寬比1.5
  • iPhone5(s):分辨率1136*640,高寬比1.775
  • iPhone6:分辨率1334*750,高寬比1.779
  • iPhone6+:分辨率1920*1080,高寬比1.778

    可粗略認爲iPhone5(s)、6(+)的高寬比是一致的(16:9),便可以等比例縮放。所以能夠按寬度適配:
        fitScreenWidth= width*(SCREEN_WIDTH/320)
    這樣,共有iPhone3/4/五、六、6+三組寬度,在iPhone六、6+下將按比例橫向放大。

(2)按高度適配

    在一樣的寬度下,iPhone4(s)的屏高比iPhone5(s)低,若縱向排版緊張,能夠iPhone5(s)爲基準,按高度適配:
        fitScreenHeight= height*(SCREEN_HEIGHT/568)
    共有iPhone3/四、五、六、6+四組高度,在iPhone3/4下將按比例縱向縮小,在iPhone六、6+下將按比例縱向放大。

    這裏須要注意iPhone/iOS雙環上網的熱點欄對縱向佈局的影響:iPhone做爲我的熱點且有鏈接時,系統狀態欄下面會多一行熱點鏈接提示欄"Personal Hotspot: * Connection",縱向會下壓20pt,[UIApplication sharedApplication].statusBarFrame高度變爲40pt;當全部鏈接都斷開時,熱點欄消失,縱向高度恢復正常爲20pt。詳情可參考《iPhone/iOS開啓我的熱點的縱向適配小結》。

(3)按字體適配

    另外,iPhone的【設置】【通用】【輔助功能】中能夠設置調節【更大字體】,APP也能夠按字號適配:
    例如適配表視圖(UITableView:UIScrollView),沒法左右滑動,所以不管字號縮放比例多大,橫向都不該超過SCREEN_WIDTH。注意限定控件元素內容區域寬度以及間距,並設置適當的LineBreakMode。表視圖支持上下滑動,所以縱向上的表格行高和內容區域高度可按字號縮放。

    對於縱向也不支持滑動的視圖,在屏幕可見視區內排版時,最好不要隨字號縮放,不然可能超出既定寬高。

10.UI相對佈局

    考慮到iPhone機型的多樣性,不可能針對iPhone4(s)、5(s)、六、6+四種屏幕尺寸出四套視覺交互稿,也不要基於某一機型從上往下、從左往右給絕對標註,而應該關注subView在superView中的相對位置(EdgeInsets/Frame/Center)以及siblingView之間的偏移(Offset),儘可能給出適合Autolayout的相對佈局比例(理想狀況是隻給百分比)。假如交互按照iPhone5(s)下絕對標註,則在iPhone4(s)上可能擠出屏幕底部,而在iPhone6(+)上則可能橫向偏左或縱向偏上。

    開發人員基於與屏幕邊緣的間距(Margin/EdgeInsets),定位邊緣處的控件(釘釘子)做爲參照,而後基於控件尺寸和間隙進行相對計算排版。這樣,若釘子移動,相鄰控件將順向偏移,不會由於局部調整而出現凌亂

    咱們截取 iPhone5s QQ 文件助手列表中的文件cell,使用 Sketch Measure 對其進行測量標註。

  打開[截圖.png]文件,因爲不包含 Sketch 圖元對象,沒法進行 measure 標註(提示:請在畫板中使用該功能)。所以,第一步須要對要相對標註的各個UI元素進行對象化。依次 Insert Artboard 建立圖層 frame、thumbnail、title、detail、source、button。

  選中整個cell的frame(bounds),進行 Measure size:width=640px(SCREEN_WIDTH),height=168px。默認橫向尺寸和縱向參考線都居中致使標註重疊,將縱向參考線右移至合適位置;也可選中WIDTH標註圖層中的text和label元素,在不移動參考線的前提下,利用鼠標局部移動標註字面量。

(1)縮略圖標

  • 在左側邊欄layer list中選中frame,再command選中文件類型縮略圖對象thumbnail,進行 Measure spacing,丈量縮略圖左側相對frame的間距爲24px。
  • 選中文件類型縮略圖對象thumbnail,進行 measure size,因爲正方形等寬爲112px*112px,故橫縱標註重疊無影響。thumbnail在frame中縱向總體居中,所以上下邊距計算均攤便可,無需再給定標註。

(2)傳輸按鈕

  • 對 button 和 frame 進行 Measure spacing,丈量按鈕右側相對frame的間距爲24px。
  • 選中按鈕button進行 measure size,其寬高爲144px*60px。橫縱標註重疊影響視覺,將縱向參考線右移至合適位置。
  • button在frame中縱向總體居中,所以上下邊距計算均攤便可,無需再給定標註。

(3)文件信息

  • 對thumbnail和detail(title、source等寬且左對齊)進行 Measure spacing,丈量圖標右側相對detail的間距爲20px;對button和detail進行 Measure spacing,丈量按鈕左側相對detail間距爲20px。這樣,左側釘住thumbnail,右側釘住button,中間信息部分的寬度無需給定,計算被動約束的橫向餘量便可。具體編程時,調用 sizeWithFont/boundingRectWithSize 可動態計算每行 label 的天然寬度,通常title都會超過約束寬度,所以需設置 lineBreakMode指定Wrapping省略或Truncating截斷格式。
  • 選中文件信息第1行標題title和第2行詳情detail,進行 Measure spacing,測量縱向相對間距10px;第2行詳情detail和第3行來源的縱向相對間距也爲10px。通常 UILabel 的文本在給定字體下的縱向天然顯示無約束,調用 sizeWithFont/boundingRectWithSize 可動態計算每行 label 的天然高度,title的上間距和source的底間距無需給定,經過計算縱向餘量均攤便可。

    可簡單的基於屏寬橫縱比例進行scale縮放,將以上測量出的標註應用到iPhone6(+)大屏下,固然交互設計工程師最好仍是針對特定機型都給定適配標註。蘋果在WWDC2012 iOS6中已提出了Auto Layout的概念,即便用約束條件來定義視圖的位置和尺寸,以適應不一樣尺寸和分辨率的屏幕。

相關文章
相關標籤/搜索