Retinaディスプレイの検出


223

iOS SDKは、currentDeviceに高解像度ディスプレイ(網膜)があるかどうかを確認する簡単な方法を提供しますか?

私が今それを行うために見つけた最良の方法は:

    if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)] == YES && [[UIScreen mainScreen] scale] == 2.00) {
         // RETINA DISPLAY
    }

好奇心から-あなたのアートワークの大きなバージョンを表示する以外にディスプレイを見つけたとき、あなたは何をしていますか?
Michael Behan


@mbehan:TTImageView(Three20フレームワークを参照)があり、画像の高解像度のURLを指定したい。
ピエールヴァレード2010

1
この質問は私にとっても役立ちます。私は、4つのディスプレイサイズすべてのサイズで利用可能なUIとして表示される画像をダウンロードし、ユーザーに適切なもののみをダウンロードしてもらいたいためです。
ペドロ

@mbehan:私の場合、網膜と非網膜の両方の画面で1pxのカスタムセルセパレータが必要でした(ネイティブセパレータのように)。厚さを1pxに設定すると、Retinaディスプレイで(当然)2pxでレンダリングされます。
user3099609 2014

回答:


295

すべてのiOSデバイスでRetinaディスプレイを確実に検出するには、デバイスがiOS4 +を実行しているかどうか、および[UIScreen mainScreen].scaleプロパティが2.0に等しいかどうかを確認する必要があります。scaleiPad 3.2にもこのプロパティが含まれているため、プロパティが存在する場合、デバイスがiOS4 +を実行していると想定することはできません。

iOS3.2を実行しているiPadでは、デバイスにRetinaディスプレイが含まれていないことがわかっていても、scaleは1xモードでは1.0、2xモードでは2.0を返します。Appleは、iPadのiOS4.2でこの動作を変更しました。1xモードと2xモードの両方で1.0を返します。これはシミュレータで自分でテストできます。

-displayLinkWithTarget:selector:iOS4.xには存在するがiOS3.2には存在しないメイン画面でメソッドをテストしてから、画面のスケールを確認します。

if ([[UIScreen mainScreen] respondsToSelector:@selector(displayLinkWithTarget:selector:)] &&
    ([UIScreen mainScreen].scale == 2.0)) {
  // Retina display
} else {
  // non-Retina display
}

「AppleはiOS4.2でiPadのこの動作を変更しました」と言っています。つまり、iOS4.1では、2xモードでiPhoneアプリを実行しているiPadで上記のコードが「is Retina」を返すことを意味します。私が間違っている?
マクダッド2012年

9
iPadには4.1はありませんでした。3.2のみ、次に4.2。
ジョニー

11
この呼び出しは少し負荷が高いので、アプリの起動時にBOOLを初期化してアプリで使用します。
n13

を使用してバージョンを確認することを好み[UIDevice currentDevice].systemVersion]ます。この場合、それはなるだろう NSString *currentSystemVersion = [[UIDevice currentDevice] systemVersion]; return [currentSystemVersion compare:version options:NSNumericSearch];
サンディ・チャップマン

xcode 4の非網膜iPad(iOS 7.1)のシミュレータでは動作しないようです...奇妙です。
アイザックポール

81

@sickpの答えは正しいです。簡単にするために、Shared.pchファイルに次の行を追加します。

#define IS_RETINA ([[UIScreen mainScreen] respondsToSelector:@selector(displayLinkWithTarget:selector:)] && ([UIScreen mainScreen].scale >= 2.0))

次に、どのファイルでも行うことができます:

if(IS_RETINA)
{
   // etc..
}

これはシミュレータでは機能しません。それは、respondsToSelectorが原因ですか?シミュレーターがセレクターに応答しませんか?
arniotaki '19

2
すごい!ただし、iPhone 6 Plusを考慮する場合は、2.0以上のスケールを確認する必要があります。
Ivan Carosati 2015

20
+(BOOL)iPhoneRetina{
    return ([[UIScreen mainScreen] respondsToSelector:@selector(displayLinkWithTarget:selector:)] && ([UIScreen mainScreen].scale == 2.0))?1:0;
}

23
なぜ?1:0?それは、式のブール部分ですでに計算されていることを繰り返すだけではないですか?
d11wtq 2013

9

ここに便利な迅速な拡張があります:

Swift v5の更新:

extension UIScreen {

    public var isRetina: Bool {
        guard let scale = screenScale else {
            return false
        }
        return scale >= 2.0
    }

    public var isRetinaHD: Bool {
        guard let scale = screenScale else {
            return false
        }
        return scale >= 3.0
    }

    private var screenScale: CGFloat? {
        guard UIScreen.main.responds(to: #selector(getter: scale)) else {
            return nil
        }
        return UIScreen.main.scale
    }
}

使用法:

if UIScreen.main.isRetina {
    // Your code
}

元の:

extension UIScreen { 
public func isRetina() -> Bool {
    return screenScale() >= 2.0
}

public func isRetinaHD() -> Bool {
    return screenScale() >= 3.0
}

private func screenScale() -> CGFloat? {
    if UIScreen.mainScreen().respondsToSelector(Selector("scale")) {
        return UIScreen.mainScreen().scale
    }
    return nil
    }
}

使用法:

if UIScreen.mainScreen().isRetina() {
 // your code
        }

Swift 5 isRetinaHDで動作するように更新されたコードは、iscreenScaleが2.0ではなく3.0以上であるかどうかを確認するべきではありませんか?編集:更新しました...
C0D3

6

このスニペット...

    int d = 0; // standard display
if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)] && [[UIScreen mainScreen] scale] == 2.0) {
    d = 1; // is retina display
}

if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
    d += 2;
}

戻ります...標準解像度のiPhone / iPod touchの場合は0、網膜iPhoneの場合は1、標準解像度iPadの場合は2、網膜iPadの場合は3。



5

浮動小数点値が等しいかどうかを比較することは常に少しおかしなことを感じます。私はどちらかに行くことを好む

[UIScreen mainScreen].scale > 1.0;

または

[UIScreen mainScreen].scale < 2.0;

5
2つの浮動小数点値が等しいかどうかを比較すると、計算後の整数値とわずかに異なる可能性があるため、「気まぐれ」になります。しかし、<または>と比較することは、これらの状況では同じように危険です。ただし、この場合、ハードウェアで定義されているため、スケールが正確に1.0または2.0ではない可能性はまったくありません。
釣り2013年

@fishinearが示唆するように、のようなものを使用することをお勧めしますisRetina = [UIScreen mainScreen].scale > 1.95。これには、@ 4xが発生したときに回復力を
発揮できる

私は強く同意しません。必要のないときにこれを行うと、コードが読みにくくなります。将来性についてのポイントはその妥当性を持っているかもしれませんが、(もしあれば)いつでも@ 4x画面が表示されることはないでしょう。
Ricardo Sanchez-Saez 2013

違う。「ハードウェアで定義」されているからといって、フロート比較の問題を回避できるわけではありません。(他のフロートと同じです。)他のフロートと同様に、一般的に==を使用することはできません。>または<の比較を使用する必要があります。確実性のために> 1.5についてはどうですか?
Fattie 2014年

2

これは、上記のMatt MCの回答のリフです。の単なるカテゴリUIScreen

#import "UIScreen+Util.h"

@implementation UIScreen (Util)

+ (BOOL) isRetinaDisplay {
    static BOOL retina = NO;
    static BOOL alreadyChecked = NO;
    if (!alreadyChecked) {
        UIScreen *mainScreen = self.mainScreen;
        if (mainScreen) {
            retina = mainScreen.scale > 1.0;
            alreadyChecked = YES;
        }
    }
    return retina;
}

@end

1
のキャッシュalreadyCheckedは不必要だと思いますが、問題ありません。
Dan Rosenstark 2013年

@NikolayShubenkovだからこそ、すでに最後に既にCheckedCheckedを設定しています。最悪のシナリオでは、コードを実行して余分な時間を確認します。
Dan Rosenstark 14

つまり、1つのプロセスがすでに他のプロセスがこの値を読み取っているときに、すでにチェック済みの状態にしようとすると、アプリがクラッシュする場合があります。私はその行を追加します:@synchronyze(alreadyChecked){alreadyChecked = YES}
Nikolay

2

上記の回答のスウィフトバージョン。2.0以上のスケールなので、iPhone 6以降と、Retinaより高いスケールを持つ他の将来のデバイスが含まれます。

 if UIScreen.mainScreen().respondsToSelector(Selector("scale")) && UIScreen.mainScreen().scale >= 2.0 {
    // code executed only on Retina device
}

1

@sickpからの回答と@ n13からの次のコメントを組み合わせるだけで、これをUIScreenカテゴリーにして、うまく機能しているように見えます。このチェックは、最初に呼び出したときに行われ、後で呼び出すために保存されます。

@interface UIScreen (RetinaCheck)
+ (BOOL)retinaScreen;
@end

static BOOL isRetinaScreen = NO;
static BOOL didRetinaCheck = NO;

@implementation UIScreen (RetinaCheck)
+ (BOOL)retinaScreen
{
    if (!didRetinaCheck) {
        isRetinaScreen = ([[self mainScreen] respondsToSelector:@selector(displayLinkWithTarget:selector:)] &&
                          ([self mainScreen].scale == 2.0));
        didRetinaCheck = YES;
    }
    return isRetinaScreen;
}
@end

誰かに役立つかもしれません。


キャッシュコードをありがとう。私の唯一の提案は、これの(Util)代わりにこれを作成すること(RetinaCheck)です...多分それは不明確ですが、それは他の用途に役立ちます。また、isRetinaDisplayで始まるメソッドなどに名前を付けますがis、Obj-Cのガイドラインを理解できなかった可能性があります。また、私はファンです> 1.0が、前進することに意味があることを知っています。
Dan Rosenstark 2013年

1
// .h
UIKIT_EXTERN bool isRetinaDisplay();

// .m
bool isRetinaDisplay()
{
    static bool flag;
#ifdef __BLOCKS__
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if([[UIScreen mainScreen] respondsToSelector:@selector(scale)])
        {
            flag = [[UIScreen mainScreen] scale] > 1.0;
        }
        else
        {
            flag = false;
        }
    });
#else
    static bool onceToken;
    if(onceToken == false)
    {
        onceToken = true;
        if([[UIScreen mainScreen] respondsToSelector:@selector(scale)])
        {
            flag = [[UIScreen mainScreen] scale] > 1.0;
        }
        else
        {
            flag = false;
        }
    }
#endif
    return flag;
}

私が思うに最良の解決策。
ニコライシュベンコフ2014

0

これを試して

if ([[UIScreen mainScreen] respondsToSelector:@selector(displayLinkWithTarget:selector:)] &&
    ([UIScreen mainScreen].scale == 2.0))
{
    // Retina display
    NSLog(@"---------------Retina display");
} else {
    // non-Retina display
    NSLog(@"---------------non-Retina display");
}

0

最も一般的な使用例を簡単にするために、primulaverisの修正バージョン。私はSwift 2.2を使用していますが、問題にはなりません。

extension UIScreen {
    static var isRetina: Bool {
        return screenScale >= 2.0
    }

    static var isRetinaHD: Bool {
        return screenScale >= 3.0
    }

    static var screenScale:CGFloat {
        return UIScreen.mainScreen().scale
    }
}

次に、単にこのように使用します

print(UIScreen.isRetina)
print(UIScreen.isRetinaHD)
print(UIScreen.screenScale)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.