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

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

未適配前: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的屏幕尺寸分辨率(上圖中 高度812 = 2436縮小1/3):

設備 屏幕尺寸分辨率 圖片存放對應的位置
iPhoneX (1倍 @1x) 375x812 @1x
iPhoneX (2倍 @2x) 750x1624 @2x
iPhoneX (3倍 @3x) 1125x2436 @3x
iPhoneX/iPhoneXs/iPhoneXs Max/iPhoneXr的屏幕尺寸分辨率

iPhoneX系列的分辨率

iPhoneX系列的屏幕分辨率:

設備 屏幕分辨率 圖片存放的位置
iPhoneX (3倍 @3x) 1125x2436 @3x
iPhoneXs (3倍 @3x) 1125x2436 @3x
iPhoneXs Max (3倍 @3x) 1242x2688 @3x
iPhoneXr (2倍 @2x) 828x1792 @2x
根據以上iPhoneX系列的屏幕分辨率,得出高寬比Ratio都爲2.16

各款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

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

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

源碼傳送門: https://github.com/apiapia/Br...
更多遊戲教程: http://www.iFIERO.com -- 爲遊戲開發深感自豪

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章