如何适配不同的iPhone、iPhoneX及iPad的螢幕尺寸,如何适配不同的iPhone、iPhoneX及iPad的螢幕尺寸呢?
我們開發一個App的時候, 通常希望它在 iPhone, iPad, Mac上同時能運作, 尤其是遊戲。
這樣就需要我們考慮不同裝置不同的分辨率,但處理起來比較麻煩,比如說,按照官方的做法,我們需要提供諸如 ifiero@1x,ifiero@2x,ifiero@3x, 這樣不同尺寸的圖檔,那如何簡便的适配裝置不同的分辨率呢,我們的做法是, 固定一個大小, 向下相容不同的裝置。
即場景中的所有圖檔, 都按照螢幕大小為 2048 * 1536 來繪制。 也就是說, 我們的背景圖的大小是 2048 * 1536, 其他圖檔也是依照這個比
未适配前:Ball球超過螢幕的上下方
适配後:Ball球就在螢幕的可視範圍内運動了
一、那麼如何适配不同的iPhone、iPhoneX及iPad的螢幕尺寸呢?
我們開發一個App的時候, 通常希望它在 iPhone, iPad, Mac上同時能運作, 尤其是遊戲。
這樣就需要我們考慮不同裝置不同的分辨率,但處理起來比較麻煩,比如說,按照官方的做法,我們需要提供諸如 ifiero@1x,ifiero@2x,ifiero@3x, 這樣不同尺寸的圖檔,那如何簡便的适配裝置不同的分辨率呢,我們的做法是, 固定一個大小, 向下相容不同的裝置。
即場景中的所有圖檔, 都按照螢幕大小為 2048 * 1536 來繪制。 也就是說, 我們的背景圖的大小是 2048 * 1536, 其他圖檔也是依照這個比例來繪制。
為什麼這樣做呢?
我們知道 2048 * 1536 是iPad Retina 的分辨率。也是我們需要适配的裝置裡面分辨率最高的。 是以我們在遊戲中都選擇了這個大小,讓它來相容分辨率低的裝置。 2048 * 1536 在iPad Retina上是完美顯示的。 那在其他裝置上呢? 這裡就要依靠 AspectFill來進行縮放了,代碼如下:
if let scene = GameScene(fileNamed: "GameScene") {
scene.size = CGSize(width: 2048, height: 1536)
scene.scaleMode = .aspectFill /// 縮放
view.presentScene(scene)
}
不同尺寸的iPhone的螢幕尺寸比例
橙色整體區域表示我們場景的真實大小, 黑色線框内的區域表示場景展示在裝置上的真實大小。
iPad Retina:橙色區域和黑色線框内的區域是完美吻合的,也就是說在裝置上能完整顯示。
iPhone6/7/8/Plus:黑色線框内的區域是2048 * 1152,這邊要注意的是,超出黑色框的内容看不見,設計遊戲時,盡量不要把精靈的Position位置放在位于不可見的區域。
不同尺寸的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 | -- | 2.16 |
iPhoneX的Safe Area為觸發互動行為的區域
iPhoneX的Safe 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) ? 44.0 : 0
public let AREA_INSET_HEIGHT_BOTTOM:CGFloat = (UIScreen.main.bounds.height == 812) ? 34.0 : 0
// 橫屏(安全區域)
public let AREA_INSET_WIDTH_TOP :CGFloat = (UIScreen.main.bounds.width == 812) ? 44.0 : 0
public let AREA_INSET_WIDTH_BOTTOM :CGFloat = (UIScreen.main.bounds.width == 812) ? 34.0 : 0
public let iPhoneX_REAL_HEIGHT:CGFloat = 812.0 /// 豎屏
extension UIDevice {
/// 是不是iPhoneX ,如果是豎屏則 UIScreen.main.bounds.height == 812
public func isPhoneX() -> Bool {
if UIScreen.main.bounds.width == 812 { /// 橫屏
return true
}
return false
}
/// 是不是iPad
public func isPad() -> Bool {
if UIScreen.main.bounds.height > 812 {
return true
}
return false
}
}
2.GameScene定義可視範圍的起點及高度 (因為是橫屏,是以定義高度)
private var playableRect:CGRect! /// 可視範圍
private var playableHeight:CGFloat = 0.0 /// 可視範圍的高度
private var playableMargin:CGFloat = 0.0 /// 可視範圍的起點
override func didMove(to view: SKView) {
self.physicsWorld.gravity = CGVector(dx: 0, dy: 0)
self.physicsWorld.contactDelegate = self
initCheckDevice()
setupBall()
}
3.檢測是哪種裝置
// MARK: - 檢測是哪種裝置
func initCheckDevice(){
if UIDevice.current.isPhoneX() {
maxAspectRatio = 2.16 /// iPhoneX 2.16 ratio
}else {
maxAspectRatio = UIDevice.current.isPad() ? (4.0 / 3.0) : (16.0 / 9.0) /// iPhone 16:9,iPad 4:3
}
/// 畫出可視區域
drawPayableArea(size: self.size,ratio: maxAspectRatio)
}
4.畫出可視區域并賦于可視區域的邊屆實體特性
// MARK: - 畫出可視區域
func drawPayableArea(size:CGSize,ratio:CGFloat){
/*
/// 安全區域即使用者互動的區域,非可視區域 (iPhoneX的安全區域 < 可視區域)
let safeInsetTop = self.size.height * AREA_INSET_TOP / iPhoneX_REAL_HEIGHT
let safeInsetBottom = self.size.height * AREA_INSET_BOTTOM / iPhoneX_REAL_HEIGHT
let safeHeight = self.size.height - safeInsetTop - safeInsetBottom
*/
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)原點的位置;
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
}
這樣子Ball球就隻在可視區域内運動了
二、iPhoneX的尺寸及安全區域
iPhoneX的螢幕尺寸 375(W)x812(H)
iPhoneX的Safe Area為觸發互動行為的區域
互動行為(按鈕)須在安全區域内
安全區域
頂部狀态欄 44points
底部間隔 34points
iPhoneX的螢幕尺寸及安全區域
iPhoneX的螢幕尺寸及安全區域:
裝置 | 螢幕尺寸 | 圖檔存放的位置 | 安全區域 |
---|---|---|---|
iPhoneX | 375x812 | @1x | 375x(812 - 34 - 44),互動的起點Position(x:0,y:34) |
iPhoneX | 750x1624 | @2x | 互動的起點Position(x:0,y:2 x 34) |
iPhoneX | 1125x2436 | @3x | 互動的起點Position(x:0,y:3 x 34) |
iPhoneX | 1536x2048 | @1x | y:2048 x 34 / 812 (已知812對應34,求2048對應y的值) |
圖檔存放的位置
安全區域
// iPhone X 375*812(H) @1x
// 豎屏
public let AREA_INSET_HEIGHT_TOP :CGFloat = (UIScreen.main.bounds.height == 812) ? 44.0 : 0
public let AREA_INSET_HEIGHT_BOTTOM:CGFloat = (UIScreen.main.bounds.height == 812) ? 34.0 : 0
// 橫屏(安全區域)
public let AREA_INSET_WIDTH_TOP :CGFloat = (UIScreen.main.bounds.width == 812) ? 44.0 : 0
public let AREA_INSET_WIDTH_BOTTOM :CGFloat = (UIScreen.main.bounds.width == 812) ? 34.0 : 0
public let iPhoneX_REAL_HEIGHT:CGFloat = 812.0 /// 豎屏
/// 安全區域即使用者互動的區域,非可視區域 (iPhoneX的安全區域 < 可視區域)
let safeInsetTop = self.size.height * AREA_INSET_WIDTH_TOP / iPhoneX_REAL_HEIGHT
let safeInsetBottom = self.size.height * AREA_INSET_WIDTH_BOTTOM / iPhoneX_REAL_HEIGHT
let safeHeight = self.size.height - safeInsetTop - safeInsetBottom // 安全區域的高度
可視區域
playableHeight = size.width / ratio /// ratio為2.16
playableMargin = (size.height - playableHeight ) / 2.0
playableRect = CGRect(x: 0, y: playableMargin, width: size.width, height: playableHeight) /// 注意 scene的anchorPoint(0,0)原點的位置;
重要的一點就是要了解螢幕尺寸和安全區域的不同,通俗點講就是,螢幕尺寸可以放任何元素,但不可放互動行為,所有的使用者互動行為都要放在安全區域内。
源碼傳送門:http://www.iFIERO.com/uploads/BreakOutGameVansV.zip
更多遊戲教程: http://www.iFIERO.com