1. 程式人生 > >【iOS】bounds與native bounds的故事(放大模式的糾結)

【iOS】bounds與native bounds的故事(放大模式的糾結)

因為實習原因接觸iOS開發,做了一週多點的時間,遇到了一個棘手的需求,也因此瞭解到了關於iPhone系列適配以及放大模式的有趣規律。

“特殊”的需求

    當iPhone XS MAX/XR使用者使用只適配了iPhone X/iPhone XS,並且隱藏了狀態列的應用,同時沒有啟動放大模式且為豎屏時,進行UI處理。
    注:應用的適配是我們無法決定的,處理的是一個獨立於應用的懸浮窗的UI。只考慮豎屏。

這樣表述的需求其實有點繞,解釋一下: 當iPhone XS MAX/XR使用者在放大模式執行應用,我們的UI不會出任何問題; 當用戶在標準模式執行應用,應用設定隱藏狀態列,UI沒有問題; 當用戶在標準模式運行了只做了X/XS適配的(一般來說就是沒有配launch image)應用,會出現UI被MAX“劉海”遮擋問題(其他情況下iPhone都能把UI往下推44單位)。 總結下來,狀態列比較好確定,機型判斷也不是問題,所以需求的核心是這樣的: 識別出應用只做了X/XS適配並且使用者沒有開啟放大模式的情況。

  1. 識別出應用只做了X/XS適配 。這裡的思路是讀取[UIScreen mainScreen] bounds].size(以下簡稱bounds)的值。
  2. 使用者有沒有開啟放大模式。當用戶開啟了放大模式,iPhone也會幫助我們完成UI調整,主要問題在於bounds在只做了低版本適配時的標準與放大模式有一樣的值,需要使用native bounds來區分 。

下面分開講講。

注:6,6s,7,8具有一樣的表現,以下統稱6;6plus,6s plus,7plus,8plus具有一樣的表現,以下統稱6plus.

bounds的表現

在MAX上做了MAX/XR適配時bounds的值是414X896,只做了X/XS適配時的值是375X812。 這個值是什麼意思呢?

@property(class, nonatomic, readonly) UIScreen *mainScreen;      // the device's internal screen

這個是程式碼上的註釋,其實網上也有很多資料說的更清晰,這個bounds其實就是“邏輯解析度”,iPhone會把邏輯解析度調整到“最適配”的數值上。

適配的優先順序:
MAX/XR > X/XS >6plus>5>4 (機型==MAX/XR)
X/XS>6>5>4 (機型==X/XS)
6plus>5>4 (機型==6plus)
6>5>4 (機型==6)
以上均經過實機驗證

舉例: 如果你的裝置是MAX,應用只適配了5,那麼bounds的值就是5的邏輯解析度320X568 如果你的裝置是X,應用適配了6和5,那麼bounds的值就是6的邏輯解析度375X667 這裡需要注意的是6和6plus只能二選一,這樣看起來MAX/XR就像是X/XS的plus版本。,。 總而言之bounds很好的體現了應用的適配情況。

放大模式做了些什麼

實際上,當處於標準模式並且適配MAX/XR時,蘋果會自動把我們的UI往下推,同時如果適配了比X更低版本時,表現也是沒問題的。 這讓我懷疑要不就是我手裡的UI對X有什麼不可告人的處理,或者是蘋果考慮少了MAX/XR在應用只適配X時的情況。 拋開這些考慮還是要解決問題的,事情在加入了放大模式之後變得有些複雜,bounds變得不再可靠了。 具體的場景就是,拿著一臺MAX興高采烈的開啟一個只適配了X的豎屏遊戲,結果最頂上的計分板被劉海遮住了,只要開啟放大模式就解決了問題。 程式設計師有點懶不想為遊戲做MAX的適配(其實是做不到),於是他運行遊戲列印了bounds值,結果發現標準模式和放大模式的bounds一樣的 為什麼呢? 我的解釋是因為這兩個模式在運行遊戲時使手機變得一樣了。 回到放大模式做了些什麼,實際上是讓整個系統變成了上一個版本的裝置

MAX/XR -> X/XS //未驗證
X/XS 沒有放大模式
6plus ->6//千萬注意不是5
6 ->5
6版本一下沒有放大模式

放大優先於適配,這意味著你的MAX變成了X,然後進行了X的適配,這和MAX只做了X的適配是“邏輯”上一樣的,因此bounds也相同了。

Native Bounds究竟是什麼

這時候就需要一個不同於bounds的屬性來區分在相同邏輯解析度(相同的適配條件)下的標準和放大模式了。或許是運氣查到了native bounds屬性

@property(nonatomic, readonly) CGRect nativeBounds;

你要問我這個屬性的真正意義,我會底氣十分不足的說這個就是“物理解析度”。 為什麼底氣不足呢?因為它是會變的,這無疑和我們所理解的物理解析度大相徑庭。 在完美適配的情況下,無論標準還是放大模式下native bounds都是裝置的真正的物理解析度(比如說MAX是1242X2688,X是1125X2436,6plus是1080X1920)。 何謂之完美呢?你適配了當前機型和放大模式機型就叫做完美,這個時候標準模式用著當前機型的邏輯解析度,而放大模式用著另一個機型的邏輯解析度。 這時候如果取消了當前機型的適配會出現什麼後果呢?顯然的一點是bounds會變的一樣,而nativebounds的表現就直接看圖吧。

6標準模式 bounds native bounds
適配6 375X667 750X1334
適配5 320X568 640X1136
適配4 320X480 640X960
6放大模式 bounds native bounds
適配6 320X568 750X1334
適配5 320X568 750X1334
適配4 320X480 750X1125

這個圖表基本完全說明了native bounds的表現規律。 標準模式下,按照適配6的bounds同比例變化; 放大模式下,按照適配5的bounds同比例變化。

簡要來說有這個結論,標準模式下和放大模式下,bounds相同時native bounds不會相同。 嗯。不要和我說MAX和XR的事情,謝謝。

問題的解決

其實問題的根源在於MAX在面對只適配X的應用時的區別對待,如果能做到一視同仁,其實也就沒有區分放大模式的必要了。 最後需求的解決說簡單也簡單,把應用的bounds讀出來,如果是X的邏輯解析度那就再比較一下MAX標準模式下適配X時的native bounds,不相等就認為是放大模式了。 這有個明顯的隱患,native bounds是否能夠一直維持其穩定性和唯一性?這顯然不是蘋果這一句話能讓人放心的:

The bounding rectangle of the physical screen, measured in pixels.

具體還有一些其他判斷和巨集定義,對文章主要內容沒有什麼關聯,就不放上來了。 希望寫明瞭自己遇到的問題、解決的方法以及思考(總感覺有更簡單的方法。,。),可能有些地方更多是猜測,歡迎各位大佬指教。