私のiOSアプリはUINavigationBar
にカスタムの高さを使用しているため、新しいiPhone Xではいくつかの問題が発生します。
アプリがiPhone X上で実行されている場合、/ Objective-Cで信頼できるをプログラムで検出する方法を既に知っていますか。
EDIT:
もちろん、画面のサイズをチェックすることは可能ですが、iOSを検出するためのTARGET_OS_IPHONE
のような「組み込み」メソッドがあるのでしょうか。
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
if (screenSize.height == 812)
NSLog(@"iPhone X");
}
編集2:
私の質問がリンクされた質問の複製であるとは思わない。もちろん、現在のデバイスのさまざまな特性を「測定」し、その結果を使用してどのデバイスを使用するかを決定する方法があります。しかし、私が最初の編集で強調しようとしたので、これは私の質問の実際のポイントではありませんでした。
"現在のデバイスがiPhone Xであるかどうかを直接検出することは可能ですか(例えば、SDKの機能によって)、間接測定を使用する必要がありますか??
これまでの答えでは、答えは「いいえ、直接的な方法はありません。測定は進むべき道です」と考えています。
あなたの質問に基づいて、答えはノーです。直接的な方法はありません。より多くの情報のためにあなたはここで情報を得ることができます:
そして
IPhone Xの高さは2436 pxです
デバイスの画面サイズと解像度 から::
デバイスの画面サイズと向き :から:
Swift 3以降 :
if UIDevice().userInterfaceIdiom == .phone {
switch UIScreen.main.nativeBounds.height {
case 1136:
print("iPhone 5 or 5S or 5C")
case 1334:
print("iPhone 6/6S/7/8")
case 1920, 2208:
print("iPhone 6+/6S+/7+/8+")
case 2436:
print("iPhone X, XS")
case 2688:
print("iPhone XS Max")
case 1792:
print("iPhone XR")
default:
print("Unknown")
}
}
目的語C :
if([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
switch ((int)[[UIScreen mainScreen] nativeBounds].size.height) {
case 1136:
printf("iPhone 5 or 5S or 5C");
break;
case 1334:
printf("iPhone 6/6S/7/8");
break;
case 1920, 2208:
printf("iPhone 6+/6S+/7+/8+");
break;
case 2436:
printf("iPhone X, XS");
break;
case 2688:
printf("iPhone XS Max");
break;
case 1792:
printf("iPhone XR");
break;
default:
printf("Unknown");
break;
}
}
Xamarin.iOS :
if (UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Phone) {
if ((UIScreen.MainScreen.Bounds.Height * UIScreen.MainScreen.Scale) == 1136) {
Console.WriteLine("iPhone 5 or 5S or 5C");
} else if ((UIScreen.MainScreen.Bounds.Height * UIScreen.MainScreen.Scale) == 1334) {
Console.WriteLine("iPhone 6/6S/7/8");
} else if ((UIScreen.MainScreen.Bounds.Height * UIScreen.MainScreen.Scale) == 1920 || (UIScreen.MainScreen.Bounds.Height * UIScreen.MainScreen.Scale) == 2208) {
Console.WriteLine("iPhone 6+/6S+/7+/8+");
} else if ((UIScreen.MainScreen.Bounds.Height * UIScreen.MainScreen.Scale) == 2436) {
Console.WriteLine("iPhone X, XS");
} else if ((UIScreen.MainScreen.Bounds.Height * UIScreen.MainScreen.Scale) == 2688) {
Console.WriteLine("iPhone XS Max");
} else if ((UIScreen.MainScreen.Bounds.Height * UIScreen.MainScreen.Scale) == 1792) {
Console.WriteLine("iPhone XR");
} else {
Console.WriteLine("Unknown");
}
}
次のようにあなたの質問に基づいて:
あるいはscreenSize.height
をint 812.0f
ではなくfloat 812
として使用してください。
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
// 812.0 on iPhone X, XS
// 896.0 on iPhone XS Max, XR.
if (screenSize.height >= 812.0f)
NSLog(@"iPhone X");
}
詳細については、iOSヒューマンインタフェースガイドラインの次のページを参照してください。
スイフト :
topNotch
で検出します。
var hasTopNotch: Bool {
if #available(iOS 11.0, *) {
return UIApplication.shared.delegate?.window??.safeAreaInsets.top ?? 0 > 20
}
return false
}
目的語C :
- (BOOL)hasTopNotch {
if (@available(iOS 11.0, *)) {
return [[[UIApplication sharedApplication] delegate] window].safeAreaInsets.top > 20.0;
}
return NO;
}
_ update _ :
userInterfaceIdiomのドキュメント で説明されているように、デバイスタイプの識別にuserInterfaceIdiom
プロパティを使用しないでください。
ユニバーサルアプリケーションの場合は、このプロパティを使用して、特定の種類のデバイスに合わせてアプリケーションの動作を調整できます。たとえば、iPhoneとiPadのデバイスでは画面サイズが異なるため、現在のデバイスの種類に基づいて異なるビューとコントロールを作成することをお勧めします。
つまり、このプロパティは実行中のアプリの表示スタイルを識別するためだけに使用されます。ただし、iPhoneアプリケーション(ユニバーサルではない)は、App storeを介してiPadデバイスにインストールできます。その場合、userInterfaceIdiom
はUIUserInterfaceIdiomPhone
も返します。
正しい方法はuname
でマシン名を取得することです。詳細については、以下を確認してください。
もう1つの可能性。iOS11とiOS 12で動作するのは、iPhone Xが一番上にノッチと44のインセットを持つ唯一のものだからです。
Objective-C:
BOOL iPhoneX = NO;
if (@available(iOS 11.0, *)) {
UIWindow *mainWindow = [[[UIApplication sharedApplication] delegate] window];
if (mainWindow.safeAreaInsets.top > 24.0) {
iPhoneX = YES;
}
}
Swift 4:
/// Has safe area
///
/// with notch: 44.0 on iPhone X, XS, XS Max, XR.
///
/// without notch: 20.0 on iPhone 8 on iOS 12+.
///
static var hasSafeArea: Bool {
guard #available(iOS 11.0, *), let topPadding = UIApplication.shared.keyWindow?.safeAreaInsets.top, topPadding > 24 else {
return false
}
return true
}
もちろん、横向きの場合は、左右の安全領域の差し込みを確認する必要があります。
編集:_windowはAppDelegateのUIWindowです。このチェックはアプリケーションのdidFinishLaunchingWithOptionsで行われます。
iOS 12用に更新され、top> 0ではなくtop> 24かどうかがチェックされます
編集:シミュレータでは、ハードウェア、着信ステータスバーの切り替えに行くことができます。こうすることで、通話中にiOS 11のiPhone XまたはiPhone XS iOS 12のステータスバーの高さが変わらないことがわかります。どちらも変化するのは時間アイコンで、どちらも緑色の背景色になります。これが簡単です。
あなたは実際の必要性に応じてiPhone Xの異なる検出を実行するものとします。
class var hasTopNotch: Bool {
if #available(iOS 11.0, tvOS 11.0, *) {
// with notch: 44.0 on iPhone X, XS, XS Max, XR.
// without notch: 24.0 on iPad Pro 12.9" 3rd generation, 20.0 on iPhone 8 on iOS 12+.
return UIApplication.shared.delegate?.window??.safeAreaInsets.top ?? 0 > 24
}
return false
}
class var hasBottomSafeAreaInsets: Bool {
if #available(iOS 11.0, tvOS 11.0, *) {
// with home indicator: 34.0 on iPhone X, XS, XS Max, XR.
// with home indicator: 20.0 on iPad Pro 12.9" 3rd generation.
return UIApplication.shared.delegate?.window??.safeAreaInsets.bottom ?? 0 > 0
}
return false
}
class var isIphoneXOrBigger: Bool {
// 812.0 on iPhone X, XS.
// 896.0 on iPhone XS Max, XR.
return UIScreen.main.bounds.height >= 812
}
注:最終的にUIDevice.current.userInterfaceIdiom == .phone
と混在させる
注:この方法ではLaunchScreenストーリーボードまたは適切なLaunchImagesが必要です。
class var isIphoneXOrLonger: Bool {
// 812.0 / 375.0 on iPhone X, XS.
// 896.0 / 414.0 on iPhone XS Max, XR.
return UIScreen.main.bounds.height / UIScreen.main.bounds.width >= 896.0 / 414.0
}
注:この方法では、LaunchScreenストーリーボードまたは適切なLaunchImagesが必要です。
マシンIDを取得して、それを文書化された値と比較します。
class var isIphoneX: Bool {
var size = 0
sysctlbyname("hw.machine", nil, &size, nil, 0)
var machine = [CChar](repeating: 0, count: size)
sysctlbyname("hw.machine", &machine, &size, nil, 0)
let model = String(cString: machine)
return model == "iPhone10,3" || model == "iPhone10,6"
}
アナリティクスに有効なiPhone Xとしてシミュレータを含めるには:
class var isIphoneX: Bool {
let model: String
if TARGET_OS_SIMULATOR != 0 {
model = ProcessInfo.processInfo.environment["SIMULATOR_MODEL_IDENTIFIER"] ?? ""
} else {
var size = 0
sysctlbyname("hw.machine", nil, &size, nil, 0)
var machine = [CChar](repeating: 0, count: size)
sysctlbyname("hw.machine", &machine, &size, nil, 0)
model = String(cString: machine)
}
return model == "iPhone10,3" || model == "iPhone10,6"
}
IPhone XS、XS Max、およびXRを含めるには、単に「iPhone 11」で始まるモデルを探します。
return model == "iPhone10,3" || model == "iPhone10,6" || model.starts(with: "iPhone11,")
import LocalAuthentication
/// will fail if user denies canEvaluatePolicy(_:error:)
class var canUseFaceID: Bool {
if #available(iOS 11.0, *) {
return LAContext().biometryType == .typeFaceID
}
return false
}
あなたは次元に従って iPhone X deviceを検出するためにこのようにすることができます。
速い
if UIDevice().userInterfaceIdiom == .phone && UIScreen.main.nativeBounds.height == 2436 {
//iPhone X
}
目的 - C
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone && UIScreen.mainScreen.nativeBounds.size.height == 2436) {
//iPhone X
}
しかし 、
これは十分な方法ではありません。もしAppleがiPhone Xと同じ大きさの次のiPhoneを発表したらどうなるでしょう。ですから最良の方法はハードウェア文字列を使ってデバイスを検出することです。
新しいデバイスのハードウェア文字列は以下の通りです。
iPhone 8 - iPhone 10,1 または iPhone 10,4
iPhone 8 Plus - iPhone10,2 または iPhone 10,5
iPhone X - iPhone 10,3 または iPhone 10,6
デバイスモデル/マシン名 を調べてください。コード内のポイント/ピクセル数を直接使用しないでください。これは hard code であり、デバイスハードウェアには意味がありません。
#import <sys/utsname.h>
NSString* deviceName()
{
struct utsname systemInfo;
uname(&systemInfo);
return [NSString stringWithCString:systemInfo.machine
encoding:NSUTF8StringEncoding];
}
結果:
@"iPhone10,3" on iPhone X (CDMA)
@"iPhone10,6" on iPhone X (GSM)
この回答 を参照してください。
フルコード実装:
#import <sys/utsname.h>
NSString * GetDeviceModel(void)
{
static dispatch_once_t onceToken;
static NSString *strModelID = nil;
dispatch_once(&onceToken, ^{
#if TARGET_IPHONE_SIMULATOR
strModelID = NSProcessInfo.processInfo.environment[@"SIMULATOR_MODEL_IDENTIFIER"];
#else
struct utsname systemInfo;
uname(&systemInfo);
strModelID = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];
#endif
});
return strModelID;
}
// See the `Hardware strings` in https://en.wikipedia.org/wiki/List_of_iOS_devices
BOOL IsiPhoneX(void)
{
NSString *strModelID = GetDeviceModel();
return [strModelID isEqualToString:@"iPhone10,3"] || [strModelID isEqualToString:@"iPhone10,6"];
}
BOOL IsNotchiPhone(void)
{
NSString *strModelID = GetDeviceModel();
return [strModelID isEqualToString:@"iPhone10,3"] || [strModelID isEqualToString:@"iPhone10,6"] || // iPhone X
[strModelID isEqualToString:@"iPhone11,2"] || [strModelID isEqualToString:@"iPhone11,4"] || [strModelID isEqualToString:@"iPhone11,6"] || // iPhone XS (Max)
[strModelID isEqualToString:@"iPhone11,8"]; // iPhone XR
}
#define IS_IPHONE (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
#define IS_IPHONE_4 (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 480.0)
#define IS_IPHONE_5 (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 568.0)
#define IS_IPHONE_6 (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 667.0)
#define IS_IPHONE_6PLUS (IS_IPHONE && [[UIScreen mainScreen] nativeScale] == 3.0f)
#define IS_IPHONE_6_PLUS (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 736.0)
#define IS_IPHONE_X (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 812.0)
#define IS_IPHONE_XS (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 812.0)
#define IS_IPHONE_X_MAX (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 896.0)
#define IS_RETINA ([[UIScreen mainScreen] scale] >= 2.0) // 3.0 for iPhone X, 2.0 for others
#define IS_IPAD_DEVICE [(NSString*)[UIDevice currentDevice].model hasPrefix:@"iPad"]
注: - 注意してください、それは縦向きの場合にのみ正常に動作します
すべての答えを見た後、これは私がやってしまったものです:
extension UIDevice {
static var isIphoneX: Bool {
var modelIdentifier = ""
if isSimulator {
modelIdentifier = ProcessInfo.processInfo.environment["SIMULATOR_MODEL_IDENTIFIER"] ?? ""
} else {
var size = 0
sysctlbyname("hw.machine", nil, &size, nil, 0)
var machine = [CChar](repeating: 0, count: size)
sysctlbyname("hw.machine", &machine, &size, nil, 0)
modelIdentifier = String(cString: machine)
}
return modelIdentifier == "iPhone10,3" || modelIdentifier == "iPhone10,6"
}
static var isSimulator: Bool {
return TARGET_OS_SIMULATOR != 0
}
}
if UIDevice.isIphoneX {
// is iPhoneX
} else {
// is not iPhoneX
}
Pre Swift 4.1では、アプリがシミュレータ上で動作しているかどうかを確認できます。
TARGET_OS_SIMULATOR != 0
Swift 4.1以降では、 ターゲット環境のプラットフォーム状態を使用して、アプリがシミュレータ上で実行されているかどうかを確認できます :
#if targetEnvironment(simulator)
return true
#else
return false
#endif
(古い方法でもまだ動作しますが、この新しい方法は将来的にはさらに有効です)
寸法に基づいたこれらの回答はすべて、将来のデバイスでの不正な動作の影響を受けやすくなります。今日は動作しますが、来年は同じサイズで、ガラスの下にカメラなどがあり、「ノッチ」がないiPhoneがある場合はどうでしょうか。唯一のオプションがアプリを更新することである場合、それはあなたとあなたの顧客にとって貧弱なソリューションです。
「iPhone10,1」などのハードウェアモデル文字列を確認することもできますが、Appleが世界中のさまざまなキャリアに対して異なるモデル番号をリリースすることがあるため、問題があります。
正しいアプローチは、トップレイアウトを再設計するか、カスタムナビゲーションバーの高さに関する問題を解決することです(これに焦点を合わせます)。ただし、これらのいずれも行わないことにした場合は、何をしていても、これを機能させるためのハックであることを理解してくださいtoday、そしてハックを機能させ続けるために、ある時点で(おそらく複数回)修正する必要があります。
Swift 4+回答
iPhone X、XR、XS、XSMAX:
注:テストには実際のデバイスが必要です
let deviceType = UIDevice.current.modelName
switch deviceType {
case "iPhone10,3", "iPhone10,6":
print("iPhoneX")
case "iPhone11,2":
print("iPhone XS")
case "iPhone11,4":
print("iPhone XS Max")
case "iPhone11,6":
print("iPhone XS Max China")
case "iPhone11,8":
print("iPhone XR")
default:
break
}
extension UIDevice {
var modelName: String {
var systemInfo = utsname()
uname(&systemInfo)
let machineMirror = Mirror(reflecting: systemInfo.machine)
let identifier = machineMirror.children.reduce("") { identifier, element in
guard let value = element.value as? Int8, value != 0 else { return identifier }
return identifier + String(UnicodeScalar(UInt8(value)))
}
return identifier
}
}
はい、可能です。 UIDevice-Hardware拡張機能 をダウンロードして(またはCocoaPodの 'UIDevice-Hardware'を使ってインストールして)次のコマンドを使います
NSString* modelID = [[[UIDevice currentDevice] modelIdentifier];
BOOL isIphoneX = [modelID isEqualToString:@"iPhone10,3"] || [modelID isEqualToString:@"iPhone10,6"];
これはシミュレータでは機能せず、実際のデバイスでのみ機能することに注意してください。
私はそれが Swift だけの解決策であることを知っています、しかしそれは誰かを助けることができます。
私はすべてのプロジェクトでglobals.Swift
を持っています、そして私がいつも追加するものの1つはユーザーのデバイスを簡単に検出するためのDeviceType
です:
struct ScreenSize {
static let width = UIScreen.main.bounds.size.width
static let height = UIScreen.main.bounds.size.height
static let frame = CGRect(x: 0, y: 0, width: ScreenSize.width, height: ScreenSize.height)
static let maxWH = max(ScreenSize.width, ScreenSize.height)
}
struct DeviceType {
static let iPhone4orLess = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxWH < 568.0
static let iPhone5orSE = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxWH == 568.0
static let iPhone678 = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxWH == 667.0
static let iPhone678p = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxWH == 736.0
static let iPhoneX = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxWH == 812.0
static let iPhoneXRMax = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxLength == 896.0
static var hasNotch: Bool {
return iPhoneX || iPhoneXRMax
}
}
それを使用するには:
if DeviceType.hasNotch {
print("This executes on all phones with a notch")
}
if DeviceType.iPhone678 {
print("This executes on iPhones 6, 7 and 8")
}
プロジェクトでLaunchImage
を使用する場合、UIScreen.main.bounds
はそれらがないと適切な値を返さないため、サポートされているすべてのデバイス(XS Max、XRなど)にイメージを追加してください。
Swift 4 再利用可能 拡張子
public extension UIDevice {
public enum `Type` {
case iPad
case iPhone_unknown
case iPhone_5_5S_5C
case iPhone_6_6S_7_8
case iPhone_6_6S_7_8_PLUS
case iPhone_X_Xs
case iPhone_Xs_Max
case iPhone_Xr
}
public var hasHomeButton: Bool {
switch type {
case .iPhone_X_Xs, .iPhone_Xr, .iPhone_Xs_Max:
return false
default:
return true
}
}
public var type: Type {
if userInterfaceIdiom == .phone {
switch UIScreen.main.nativeBounds.height {
case 1136:
return .iPhone_5_5S_5C
case 1334:
return .iPhone_6_6S_7_8
case 1920, 2208:
return .iPhone_6_6S_7_8_PLUS
case 2436:
return .iPhone_X_Xs
case 2688:
return .iPhone_Xs_Max
case 1792:
return .iPhone_Xr
default:
return .iPhone_unknown
}
}
return .iPad
}
}
@ saswanbの回答によると、これはSwift 4バージョンです。
var iphoneX = false
if #available(iOS 11.0, *) {
if ((UIApplication.shared.keyWindow?.safeAreaInsets.top)! > CGFloat(0.0)) {
iphoneX = true
}
}
height
を使用しているすべての答えは、1つの理由でストーリーの半分に過ぎません。デバイスの向きがlandscapeLeft
またはlandscapeRight
のときにそのようにチェックしようとすると、height
がwidth
と入れ替えられるため、チェックは失敗します。
Swift 4.0で私の解決策がこんな風に見えるのはそのためです。
extension UIScreen {
///
static var isPhoneX: Bool {
let screenSize = UIScreen.main.bounds.size
let width = screenSize.width
let height = screenSize.height
return min(width, height) == 375 && max(width, height) == 812
}
}
AppleがUINavigationBarの高さを変えてリリースした唯一のデバイスがiPhone Xになるとは限りません。より一般的な解決策を使用してこの問題を解決してみてください。バーを常にデフォルトの高さより20ピクセル大きくしたい場合は、コードを64ピクセル(44ピクセル+ 20ピクセル)に設定するのではなく、バーの高さに20ピクセルを追加する必要があります。
スイフト3 + 4:
任意のデバイスサイズのピクセル値を必要とせず
//UIApplication+SafeArea.Swift
extension UIApplication {
static var isDeviceWithSafeArea:Bool {
if #available(iOS 11.0, *) {
if let topPadding = shared.keyWindow?.safeAreaInsets.bottom,
topPadding > 0 {
return true
}
}
return false
}
}
例:
if UIApplication.isDeviceWithSafeArea {
//e.g. change the frame size height of your UITabBar
}
struct ScreenSize {
static let width = UIScreen.main.bounds.size.width
static let height = UIScreen.main.bounds.size.height
static let maxLength = max(ScreenSize.width, ScreenSize.height)
static let minLength = min(ScreenSize.width, ScreenSize.height)
static let frame = CGRect(x: 0, y: 0, width: ScreenSize.width, height: ScreenSize.height)
}
struct DeviceType {
static let iPhone4orLess = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxLength < 568.0
static let iPhone5orSE = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxLength == 568.0
static let iPhone678 = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxLength == 667.0
static let iPhone678p = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxLength == 736.0
static let iPhoneX = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxLength == 812.0
static let IS_IPAD = UIDevice.current.userInterfaceIdiom == .pad && ScreenSize.maxLength == 1024.0
static let IS_IPAD_PRO = UIDevice.current.userInterfaceIdiom == .pad && ScreenSize.maxLength == 1366.0
}
他のソリューションで提案されているように、画面のピクセルサイズを使用しないでください。これは、将来のデバイスで誤検知が発生する可能性があるため、不適切です。 UIWindowがまだレンダリングされていない場合(AppDelegate)、ランドスケープアプリでは機能せず、スケールが設定されている場合はシミュレーターで失敗する可能性があります。
代わりに、この目的のためにマクロを作成しました。非常に使いやすく、前述の問題を防ぐためにハードウェアフラグに依存しています。
編集:iPhoneX、iPhone XS、iPhoneXR、iPhoneXS Maxをサポートするように更新
if (IS_DEVICE_IPHONEX) {
//do stuff
}
うん、本当に。
これを任意の場所にコピーして貼り付けます。@end
の後の.hファイルの一番下を好みます
#import <sys/utsname.h>
#if TARGET_IPHONE_SIMULATOR
#define IS_SIMULATOR YES
#else
#define IS_SIMULATOR NO
#endif
#define IS_DEVICE_IPHONEX (\
(^BOOL (void){\
NSString *__modelIdentifier;\
if (IS_SIMULATOR) {\
__modelIdentifier = NSProcessInfo.processInfo.environment[@"SIMULATOR_MODEL_IDENTIFIER"];\
} else {\
struct utsname __systemInfo;\
uname(&__systemInfo);\
__modelIdentifier = [NSString stringWithCString:__systemInfo.machine encoding:NSUTF8StringEncoding];\
}\
NSString *__iPhoneX_GSM_Identifier = @"iPhone10,6";\
NSString *__iPhoneX_CDMA_Identifier = @"iPhone10,3";\
NSString *__iPhoneXR_Identifier = @"iPhone11,8";\
NSString *__iPhoneXS_Identifier = @"iPhone11,2";\
NSString *__iPhoneXSMax_China_Identifier = @"iPhone11,6";\
NSString *__iPhoneXSMax_Other_Identifier = @"iPhone11,4";\
return ([__modelIdentifier isEqualToString:__iPhoneX_GSM_Identifier] || [__modelIdentifier isEqualToString:__iPhoneX_CDMA_Identifier] || [__modelIdentifier isEqualToString:__iPhoneXR_Identifier] || [__modelIdentifier isEqualToString:__iPhoneXS_Identifier] || [__modelIdentifier isEqualToString:__iPhoneXSMax_China_Identifier] || [__modelIdentifier isEqualToString:__iPhoneXSMax_Other_Identifier]);\
})()\
)
#define IS_IPHONE (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
#define IS_IPHONE_X (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 812.0f)
通常、プログラマーは上または下に制限するためにそれを必要とします。
static func extraTop() -> CGFloat {
var top: CGFloat = 0
if #available(iOS 11.0, *) {
if let t = UIApplication.shared.keyWindow?.safeAreaInsets.top {
top = t
}
}
return top
}
static func extraBottom() -> CGFloat {
var bottom: CGFloat = 0
if #available(iOS 11.0, *) {
if let b = UIApplication.shared.keyWindow?.safeAreaInsets.bottom {
bottom = b
}
}
return bottom
}
IPhone Xより前の場合、これらのメソッドは以下を返します。0
IPhone Xの場合:44と34はそれに応じて
それからこれらの追加を上または下の制約に追加するだけです。
ネイティブ境界の高さが(私のように)2436pxではなく2001pxになっているのは、iOS 11(Xcode 9ではなくXcode 8)より前の古いSDKを使ってアプリを構築したためです。古いSDKを使用すると、iOSは、画面の端から端まで、最上位の「センサーノッチ」を超えて拡張するのではなく、iPhone X上で「ブラックボックス化」されたアプリを表示します。これにより、画面サイズが縮小されるため、このプロパティは2436ではなく2001を返します。
最も簡単な解決策は、デバイスの検出だけに関心がある場合は、両方のサイズをチェックすることです。バイオメトリックタイプを指定するENUM値を持たない古いXcode SDKを使用して構築しながら、FaceIDを検出するためにこの方法を使用しました。このような状況では、画面の高さを使用したデバイス検出は、Xcodeを更新しなくても、デバイスにFaceIDとTouchIDがあるかどうかを知るための最良の方法のように見えました。
- (BOOL)isIphoneX {
if (@available(iOS 11.0, *)) {
UIWindow *window = UIApplication.sharedApplication.keyWindow;
CGFloat topPadding = window.safeAreaInsets.top;
if(topPadding>0) {
return YES;
}
else {
return NO;
}
}
else {
return NO;
}
}
私はあなたの他の答えについて詳しく述べ、UIDeviceのSwift拡張を作りました。私はSwift列挙型と「順不同」と噴霧化が好きです。私は、デバイスとシミュレータの両方で機能するソリューションを作成しました。
利点: - シンプルなインターフェース、使い方UIDevice.current.isIPhoneX
- UIDeviceModelType
enumを使用すると、アプリで使用するモデル固有の機能や定数を簡単に拡張できます。 cornerRadius
デメリット: - 解像度固有ではなく、モデル固有のソリューションです。 Appleが同じスペックで別のモデルを作成する場合、これは正しく機能しません。この機能を実現するには別のモデルを追加する必要があります。
extension UIDevice {
enum UIDeviceModelType : Equatable {
///iPhoneX
case iPhoneX
///Other models
case other(model: String)
static func type(from model: String) -> UIDeviceModelType {
switch model {
case "iPhone10,3", "iPhone10,6":
return .iPhoneX
default:
return .other(model: model)
}
}
static func ==(lhs: UIDeviceModelType, rhs: UIDeviceModelType) -> Bool {
switch (lhs, rhs) {
case (.iPhoneX, .iPhoneX):
return true
case (.other(let modelOne), .other(let modelTwo)):
return modelOne == modelTwo
default:
return false
}
}
}
var simulatorModel: String? {
guard TARGET_OS_SIMULATOR != 0 else {
return nil
}
return ProcessInfo.processInfo.environment["SIMULATOR_MODEL_IDENTIFIER"]
}
var hardwareModel: String {
var systemInfo = utsname()
uname(&systemInfo)
let machineMirror = Mirror(reflecting: systemInfo.machine)
let model = machineMirror.children.reduce("") { identifier, element in
guard let value = element.value as? Int8, value != 0 else { return identifier }
return identifier + String(UnicodeScalar(UInt8(value)))
}
return model
}
var modelType: UIDeviceModelType {
let model = self.simulatorModel ?? self.hardwareModel
return UIDeviceModelType.type(from: model)
}
var isIPhoneX: Bool {
return modelType == .iPhoneX
}
}
私はそれがiPhone Xであるかどうかを検出するためにステータスバーフレームの高さに頼る:
if UIApplication.shared.statusBarFrame.height >= CGFloat(44) {
// It is an iPhone X
}
これはアプリケーションの肖像画のためです。デバイスの向きに応じてサイズを確認することもできます。また、他のiPhoneでは、ステータスバーが隠れている可能性があるので、フレームの高さは0
です。 iPhone Xでは、ステータスバーは非表示になりません。
Peter Kreinzのコード (きれいで、必要なことをしたため)を使用していましたが、その後、デバイスが縦向きになったときに機能することに気付きました(明らかに上部パディングが上部になるので)それで、私はスクリーンサイズに頼ることなく、それぞれのパディングですべての方向を扱うための拡張を作成しました:
extension UIDevice {
var isIphoneX: Bool {
if #available(iOS 11.0, *), isIphone {
if isLandscape {
if let leftPadding = UIApplication.shared.keyWindow?.safeAreaInsets.left, leftPadding > 0 {
return true
}
if let rightPadding = UIApplication.shared.keyWindow?.safeAreaInsets.right, rightPadding > 0 {
return true
}
} else {
if let topPadding = UIApplication.shared.keyWindow?.safeAreaInsets.top, topPadding > 0 {
return true
}
if let bottomPadding = UIApplication.shared.keyWindow?.safeAreaInsets.bottom, bottomPadding > 0 {
return true
}
}
}
return false
}
var isLandscape: Bool {
return UIDeviceOrientationIsLandscape(orientation) || UIInterfaceOrientationIsLandscape(UIApplication.shared.statusBarOrientation)
}
var isPortrait: Bool {
return UIDeviceOrientationIsPortrait(orientation) || UIInterfaceOrientationIsPortrait(UIApplication.shared.statusBarOrientation)
}
var isIphone: Bool {
return self.userInterfaceIdiom == .phone
}
var isIpad: Bool {
return self.userInterfaceIdiom == .pad
}
}
そしてあなたの電話サイトであなたはただ:
let res = UIDevice.current.isIphoneX
あるいは、 ' DeviceKit 'ポッドをチェックすることもできます。
import DeviceKit
let device = Device()
if device == .iPhoneX {
// place your code here
}
私は最近同じ問題を解決しなければなりませんでした。そして、この質問に対する最終的な答え(「いいえ」)はありますが、これはiPhone X特有のレイアウトの振る舞いを必要とする他の人々を助けるかもしれません。
デバイスがiPhone Xであるかどうかにはあまり興味がありませんでした。デバイスにノッチ付きディスプレイがあるかどうかには興味がありませんでした。
private static var hasNotchedDisplay: Bool {
if let window = UIApplication.shared.keyWindow {
return (window.compatibleSafeAreaInsets.top > 20.0 || window.compatibleSafeAreaInsets.left > 0.0 || window.compatibleSafeAreaInsets.right > 0.0)
}
return false
}
同じ行に沿ってhasOnScreenHomeIndicator
変数を書くこともできます(ただし、一番下の安全領域を確認してください)。
上記はiOS 10以前のセーフエリアインセットへの便利なアクセスのためにUIView
の私の拡張子を使います。
@objc public extension UIView {
@objc public var compatibleSafeAreaInsets: UIEdgeInsets {
if #available(iOS 11.0, *) {
return safeAreaInsets
} else {
return .zero
}
}
@objc public var compatibleSafeAreaLayoutGuide: UILayoutGuide {
if #available(iOS 11.0, *) {
return safeAreaLayoutGuide
} else {
return layoutMarginsGuide
}
}
}
デバイスが何かを知りたい理由がいくつかあります。
あなたは、デバイスの高さ(と幅)を確認することができます。これはレイアウトには便利ですが、正確なデバイスを知りたい場合は通常そうしたくありません。
レイアウトの目的で、UIView.safeAreaInsets
を使うこともできます。
たとえば、診断目的で電子メールに含めるためにデバイス名を表示したい場合は、sysctl ()
を使用してデバイスモデルを取得した後、これと同等のものを使用して名前を計算できます。
$ curl http://appledevicenames.com/devices/iPhone10,6
iPhone X
Appleは、デバイスに「ノッチ」または「ホームインジケータ」があるかどうかを手動で確認したくない しかし動作するコードは次のとおりです。
-(BOOL)hasTopNotch{
if (@available(iOS 11.0, *)) {
float max_safe_area_inset = MAX(MAX([[[UIApplication sharedApplication] delegate] window].safeAreaInsets.top, [[[UIApplication sharedApplication] delegate] window].safeAreaInsets.right),MAX([[[UIApplication sharedApplication] delegate] window].safeAreaInsets.bottom, [[[UIApplication sharedApplication] delegate] window].safeAreaInsets.left));
return max_safe_area_inset >= 44.0;
}
return NO;
}
-(BOOL)hasHomeIndicator{
if (@available(iOS 11.0, *)) {
int iNumberSafeInsetsEqualZero = 0;
if([[[UIApplication sharedApplication] delegate] window].safeAreaInsets.top == 0.0)iNumberSafeInsetsEqualZero++;
if([[[UIApplication sharedApplication] delegate] window].safeAreaInsets.right == 0.0)iNumberSafeInsetsEqualZero++;
if([[[UIApplication sharedApplication] delegate] window].safeAreaInsets.bottom == 0.0)iNumberSafeInsetsEqualZero++;
if([[[UIApplication sharedApplication] delegate] window].safeAreaInsets.left == 0.0)iNumberSafeInsetsEqualZero++;
return iNumberSafeInsetsEqualZero <= 2;
}
return NO;
}
他の投稿の一部は機能しません。たとえば、縦向きモードで「通話中ステータスバー」(緑色のバー)が付いているiPhone 6Sには、一番上の安全な差し込みがあります。私のコードでは、すべてのケースが取り上げられています( デバイスが縦向きまたは横向きで起動している場合でも )
デバイスがiPhone Xであるかどうかを検出するための最善かつ最も簡単な方法は、
https://github.com/stephanheilner/UIDevice-DisplayName
var systemInfo = utsname()
uname(&systemInfo)
let machineMirror = Mirror(reflecting: systemInfo.machine)
let identifier = machineMirror.children.reduce("") { identifier, element in
guard let value = element.value as? Int8 , value != 0 else { return identifier}
return identifier + String(UnicodeScalar(UInt8(value)))}
また、iPhone Xの場合、識別子は "iPhone 10,3"または "iPhone 10,6" のいずれかです。
Portrait onlyでは、ビューのフレームの幅と高さを使ってチェックします。
override func viewDidLoad() {
super.viewDidLoad()
// iPhone Xr: -414 x 896
// iPhone Xs Max: -414 x 896
// iPhone X, Xs: -375 x 812
if view.frame.width == 414 && view.frame.height == 896 || view.frame.width == 375 && view.frame.height == 812 {
print("iPhone X")
} else {
print("not iPhone X")
}
}
IOS 12のリリースで、iPhone Xのようなデバイスがこのカテゴリに入るかもしれません。
`
extension UIDevice {
var isPortrait: Bool {
return UIDeviceOrientationIsPortrait(orientation) ||
UIInterfaceOrientationIsPortrait(UIApplication.shared.statusBarOrientation)
}
var isDeviceWith_XShape : Bool {
if self.userInterfaceIdiom == .phone {
if isPortrait
{
switch UIScreen.main.nativeBounds.height {
case 2436,2688,1792:
print("iPhone X, Xs, Xr, Xs Max")
return true
default:
print("Any other device")
return false
}
}
else
{
switch UIScreen.main.nativeBounds.width {
case 2436,2688,1792:
print("iPhone X, Xs, Xr, Xs Max")
return true
default:
print("Any other device")
return false
}
}
}
else
{
return false
}
}`
迅速な修正のために、私はこれが好きです:
let var:CGFloat = (UIDevice.current.userInterfaceIdiom == .phone && UIScreen.main.nativeBounds.height == 2436) ? <iPhoneX> : <AllOthers>
簡単な方法でデバイスを検出する。以下のように、
func isPhoneDevice() -> Bool {
return UIDevice.current.userInterfaceIdiom == .phone
}
func isDeviceIPad() -> Bool {
return UIDevice.current.userInterfaceIdiom == .pad
}
func isPadProDevice() -> Bool {
let SCREEN_WIDTH: CGFloat = UIScreen.main.bounds.size.width
let SCREEN_HEIGHT: CGFloat = UIScreen.main.bounds.size.height
let SCREEN_MAX_LENGTH: CGFloat = fmax(SCREEN_WIDTH, SCREEN_HEIGHT)
return UIDevice.current.userInterfaceIdiom == .pad && SCREEN_MAX_LENGTH == 1366.0
}
func isPhoneXandXSDevice() -> Bool {
let SCREEN_WIDTH = CGFloat(UIScreen.main.bounds.size.width)
let SCREEN_HEIGHT = CGFloat(UIScreen.main.bounds.size.height)
let SCREEN_MAX_LENGTH: CGFloat = fmax(SCREEN_WIDTH, SCREEN_HEIGHT)
return UIDevice.current.userInterfaceIdiom == .phone && SCREEN_MAX_LENGTH == 812.0
}
func isPhoneXSMaxandXRDevice() -> Bool {
let SCREEN_WIDTH = CGFloat(UIScreen.main.bounds.size.width)
let SCREEN_HEIGHT = CGFloat(UIScreen.main.bounds.size.height)
let SCREEN_MAX_LENGTH: CGFloat = fmax(SCREEN_WIDTH, SCREEN_HEIGHT)
return UIDevice.current.userInterfaceIdiom == .phone && SCREEN_MAX_LENGTH == 896.0
}
そしてこう呼んで
if isPhoneDevice() {
// Your code
}