1. 程式人生 > >適配iPhoneX、iPhoneXs、iPhoneXs Max、iPhoneXr 螢幕尺寸及安全區域

適配iPhoneX、iPhoneXs、iPhoneXs Max、iPhoneXr 螢幕尺寸及安全區域

此篇文章是對上一篇文章(http://www.ifiero.com/index.php/archives/611)的進一步補充,主要說明如何適配Apple的最新三款手機iPhoneXs、iPhoneXs Max及iPhoneXr !!!

未適配前:Ball球超過螢幕的上下方

未適配前:Ball球超過螢幕的上下方

適配後:Ball球就在螢幕的可視範圍內運動了

適配後:Ball球就在螢幕的可視範圍內運動了

回顧:為何要把場景中的所有圖片, 都按照螢幕大小為 2048 * 1536 來繪製。 也就是說, 我們的背景圖的大小是 2048 * 1536, 其他圖片也是依照這個比例來繪製。

為什麼這樣做呢?

我們知道 2048 * 1536 是iPad Retina 的解析度。也是我們需要適配的裝置裡面解析度最高的。 所以我們在遊戲中都選擇了這個大小,讓它來相容解析度低的裝置。 2048 * 1536 在iPad Retina上是完美顯示的。 那在其他裝置上呢? 先用 AspectFill來進行縮放,並應用相應的螢幕辨率高寬比值Ratio, 來適配各個不同的iPhone尺寸。AspectFill縮放的程式碼如下:

if let scene = GameScene(fileNamed: "GameScene") {
                scene.size = CGSize(width: 2048, height: 1536)
                scene.scaleMode = .aspectFill /// 縮放
                view.presentScene(scene)
 }

瞭解了用 AspectFill來進行縮放,那麼我們現在就來看看iPhoneX的螢幕尺寸解析度

以iPhoneX的解析度為例,SafeArea為安全區域

以iPhoneX的解析度為例,SafeArea為安全區域

iPhoneX的螢幕尺寸解析度(上圖中 高度812 = 2436縮小1/3):

裝置螢幕尺寸解析度圖片存放對應的位置
iPhoneX (1倍 @1x) 375×812 @1x
iPhoneX (2倍 @2x) 750×1624 @2x
iPhoneX (3倍 @3x) 1125×2436 @3x

iPhoneX/iPhoneXs/iPhoneXs Max/iPhoneXr的螢幕尺寸解析度

iPhoneX系列的解析度

iPhoneX系列的解析度

iPhoneX系列的螢幕解析度:

裝置螢幕解析度圖片存放的位置
iPhoneX (3倍 @3x) 1125×2436 @3x
iPhoneXs (3倍 @3x) 1125×2436 @3x
iPhoneXs Max (3倍 @3x) 1242×2688 @3x
iPhoneXr (2倍 @2x) 828×1792 @2x

根據以上iPhoneX系列的螢幕解析度,得出高寬比Ratio都為2.16

各款iPhone的螢幕分辨比率

各款iPhone的螢幕分辨比率

橙色整體區域表示我們場景的真實大小, 用 AspectFill來進行縮放後,scene.scaleMode = .aspectFill,黑色線框內的區域表示場景展示在裝置上的真實大小(即螢幕可視範圍)。

iPad Retina:橙色區域和黑色線框內的區域是完美吻合的,也就是說在裝置上能完整顯示。

iPhone6/7/8/Plus:黑色線框內的區域是2048 * 1152,這邊要注意的是,超出黑色框的內容看不見,設計遊戲時,儘量不要把精靈的Position位置放在位於不可見的區域。

iPhoneX:黑色線框內的區域是2048 * 948(蘭色為安全區域),其中948高度=2048 / 2.16(高寬比)。

不同尺寸的iPhone的螢幕尺寸比例及螢幕高寬比值

裝置螢幕比例螢幕高寬比值
iPad Retina 4 / 3 1.33
iPhone 6/7/8 16 / 9 1.77
iPhone 6/7/8 Plus 16 / 9 1.77
iPhone X/Xs/Xr/Xs Max 2.16

再者我們主要是適配SpriteKit遊戲開發,因為不需要計算Navigation導航欄的高度,也不需要TabBar狀態列的高度,只需要計算可視區域(螢幕可視範圍),還有,注意要把需要互動的元素放在安全區域SafeArea,而不要放在危險區域 Danger Area就行了。

可視區域(螢幕可視範圍)= 安全區域 Safe Area + 危險區域 Danger Area

瞭解了原理後,我們就開始來編寫程式碼吧。

1.extension拓展UIDevice,判斷裝置是iPhone或者iPhoneX系列或iPad

import UIKit
import SpriteKit

// iPhone X  375*812(H) @1x
// 豎屏
public let AREA_INSET_HEIGHT_TOP   :CGFloat = (UIScreen.main.bounds.height == 812 || UIScreen.main.bounds.height == 896) ? 44.0 : 0
public let AREA_INSET_HEIGHT_BOTTOM:CGFloat = (UIScreen.main.bounds.height == 812 || UIScreen.main.bounds.height == 896) ? 34.0 : 0
// 橫屏(安全區域)
public let AREA_INSET_WIDTH_LEFT  :CGFloat = (UIScreen.main.bounds.width == 812 || UIScreen.main.bounds.width == 896) ? 44.0 : 0
public let AREA_INSET_WIDTH_RIGHT :CGFloat = (UIScreen.main.bounds.width == 812 || UIScreen.main.bounds.width == 896) ? 34.0 : 0

extension UIDevice {
    /// 是不是iPhoneX ,如果是豎屏則 UIScreen.main.bounds.height == 812
    public func isPhoneX() -> Bool {
        if UIScreen.main.bounds.width == 812 || UIScreen.main.bounds.width == 896 {  /// 橫屏
            return true
        }
        return false
    }
    /// 是不是iPad
    public func isPad() -> Bool {
        return (UIDevice.current.userInterfaceIdiom == .pad) ? true : false;
    }
    
}

2.檢測是哪種裝置

  // MARK: - 檢測是哪種裝置
    func initCheckDevice(){
        if UIDevice.current.isPhoneX() {
            maxAspectRatio = 2.16         /// iPhoneX || iPhoneXs || iPhoneXs Max || iPhoneXr 2.16 高/寬比 ratio
        }else {
            maxAspectRatio  = UIDevice.current.isPad() ? (4.0 / 3.0) : (16.0 / 9.0)  /// iPhone 16:9,iPad 4:3
        }
        /// 畫出可視區域
        drawPlayableArea(size: self.size,ratio: maxAspectRatio)
        /// 畫出安全區域
        drawSafeArea(size: self.size,ratio: maxAspectRatio)
    }

3.畫出安全區域

 // MARK: - 安全區域即使用者互動的區域,非可視區域 (iPhoneX的安全區域 < 可視區域)
    func drawSafeArea(size:CGSize,ratio:CGFloat){
        
        playableHeight  = size.width / ratio
        playableMargin = (size.height - playableHeight ) / 2.0   /// P70
        
        let safeInsetLeft   =  AREA_INSET_WIDTH_LEFT * ratio
        let safeInsetRight  =  size.width - safeInsetLeft - AREA_INSET_WIDTH_RIGHT * ratio
        
        playableRect = CGRect(x: safeInsetLeft, y: playableMargin, width:safeInsetRight, height:  playableHeight)  /// 注意 scene的anchorPoint(0,0)原點的位置;
        let shapeFrame = SKShapeNode(rect: playableRect)
        shapeFrame.zPosition = 2
        shapeFrame.strokeColor = SKColor.green
        shapeFrame.lineWidth = 6.0
        addChild(shapeFrame)
        
    }

4.畫出可視區域並賦於可視區域的邊屆物理特性

 // MARK: - 畫出可視區域
    func drawPlayableArea(size:CGSize,ratio:CGFloat){
        
        playableHeight  = size.width / ratio
        playableMargin = (size.height - playableHeight ) / 2.0   /// P70
        playableRect = CGRect(x: 0, y: playableMargin, width: size.width, height:  playableHeight)  /// 注意 scene的anchorPoint(0,0)原點的位置;
        print("playable Margin",playableMargin)
        
        let shapeFrame = SKShapeNode(rect: playableRect)
        shapeFrame.zPosition = 1
        shapeFrame.strokeColor = SKColor.red
        shapeFrame.lineWidth = 5.0
        addChild(shapeFrame)
        
        /// 可視區域的物理狀態
        let playableBody = SKPhysicsBody(edgeLoopFrom: playableRect)
        playableBody.friction = 0
        self.physicsBody = playableBody
        playableBody.categoryBitMask    = PhysicsCategory.Frame
        playableBody.contactTestBitMask = PhysicsCategory.Ball
        playableBody.collisionBitMask   = PhysicsCategory.Ball
        
        /// 地板
        setupFloor()
    }

這樣子Ball球就只在可視區域內(螢幕可視範圍)運動了。

適配iPhoneXs Max

適配iPhoneXs Max

重要的一點就是要了解螢幕尺寸和安全區域的不同,通俗點講就是,螢幕可視範圍可以放任何元素,但所有的使用者互動行為都要放在安全區域內(蘭色框內)。

即可視區域(螢幕可視範圍)= 安全區域 Safe Area + 危險區域 Danger Area

更多遊戲教學:http://www.iFIERO.com