Retina Ekranını Algıla


223

İOS SDK, currentDevice'in yüksek çözünürlüklü bir ekrana (retina) sahip olup olmadığını kontrol etmenin kolay bir yolunu sunuyor mu?

Şimdi yapmanın en iyi yolu:

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

Merak etme - sanat eserinizin daha büyük versiyonlarını göstermek dışında ekranı tespit ettiğinizde ne yapıyorsunuz?
Michael Behan


@mbehan: TTImageView (bkz. Three20 çerçevesi) var ve görüntünün yüksek çözünürlüklü bir URL'sini vermek istiyorum.
Pierre Valade

1
Bu soru benim için de yararlıdır, çünkü 4 ekran boyutunun tümü için boyut olarak UI olarak sunulan görüntüleri indirdim ve yalnızca kullanıcıların uygun olanı indirmesini istiyorum.
Pedro

@mbehan: benim durumumda hem retina hem de retina olmayan ekranlarda (yerli ayırıcılar gibi) 1px olan özel hücre ayırıcılar istedim. Kalınlığın 1 piksele ayarlanması, retina ekranlarda 2 piksele dönüşür (açıkçası).
kullanıcı3099609

Yanıtlar:


295

Retina ekranını tüm iOS cihazlarda güvenilir bir şekilde tespit etmek için, cihazın iOS4 + çalıştırıp çalıştırmadığını ve [UIScreen mainScreen].scalemülkün 2.0'a eşit olup olmadığını kontrol etmeniz gerekir . Bir cihazın iOS4 + çalıştığını varsayamazsınız.scale 3.2 de bu özelliği içerdiğinden özellik varsa .

İOS3.2 çalıştıran bir iPad'de, ölçek 1x modunda 1.0 ve 2x modunda 2.0 döndürür - cihazda Retina ekran bulunmadığını bilsek bile. Apple, iPad için iOS4.2'de bu davranışı değiştirdi: hem 1x hem de 2x modlarında 1.0 döndürüyor. Bunu simülatörde kendiniz test edebilirsiniz.

-displayLinkWithTarget:selector:Ana ekranda iOS4.x'te bulunan ancak iOS3.2'de olmayan yöntemi test ediyorum ve ardından ekranın ölçeğini kontrol ediyorum:

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

"Apple, iPad için iOS4.2'de bu davranışı değiştirdi" diyerek, iOS4.1'de yukarıdaki kodunuzun, iPhone uygulamasını 2x modunda çalıştıran bir iPad için "Retina" döndüreceğini belirtiyorsunuz. Yanlış mıyım?
makdad

9
İPad için hiç 4.1 olmadı. Sadece 3.2, sonra 4.2.
Jonny

11
Bu çağrı biraz pahalı, bu yüzden ben uygulama başlangıcında onunla bir BOOL başlatmak ve app kullanmak.
n13

Sürümünü kullanarak kontrol etmeyi tercih ederim [UIDevice currentDevice].systemVersion]. Bu durumda olurdu NSString *currentSystemVersion = [[UIDevice currentDevice] systemVersion]; return [currentSystemVersion compare:version options:NSNumericSearch];
Sandy Chapman

Xcode 4 ... garip olmayan retina olmayan iPad (ios 7.1) için simülatörde çalışmıyor gibi görünüyor.
Isaac Paul

81

@ sickp'in cevabı doğru. İşleri kolaylaştırmak için bu satırı Shared.pch dosyanıza ekleyin:

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

Sonra herhangi bir dosyada şunları yapabilirsiniz:

if(IS_RETINA)
{
   // etc..
}

Bu simülatörde çalışmaz. Bu yanıtlar nedeniyleSelector? Simülatör seçiciye yanıt vermiyor mu?
arniotaki

2
Harika! Ancak, iPhone 6 Plus'ı hesaba katmak istiyorsanız, ölçek> = 2.0'ı kontrol etmelisiniz.
Ivan Carosati

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

23
Neden ?1:0? Bu sadece ifadenin boole kısmında hesaplanmış olan şeyi tekrarlamak değil mi?
d11wtq

9

İşte kullanışlı bir hızlı uzantı:

Swift v5 için güncelleme:

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
    }
}

Kullanımı:

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

Orijinal:

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
    }
}

Kullanımı:

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

Swift 5 isRetinaHD için çalışmak için güncellenen kod iscreenScale> = 3.0 2.0 değil mi kontrol edin ??? Düzenleme: Güncelledim ...
C0D3

6

Bu pasaj ...

    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;
}

Geri dönecek ... Standart çözünürlüklü iPhone / iPod touch için 0, retina iPhone için 1, standart çözünürlüklü iPad için 2, retina iPad için 3.



5

Eşitlik için kayan nokta değerlerini karşılaştırmak her zaman biraz tehlikeli hissettirir. Ben de gitmeyi tercih ederim

[UIScreen mainScreen].scale > 1.0;

veya

[UIScreen mainScreen].scale < 2.0;

5
Eşitlik için iki kayan nokta değerinin karşılaştırılması, hesaplamalardan sonra integral değerlerden biraz farklı olabileceğinden, "tehlikeli" hissettirir. Ancak <veya> ile kıyaslamak, bu gibi durumlarda tehlikeli. Ancak bu durumda donanım tanımlı olduğu için bu ölçeğin tam olarak 1.0 veya 2.0 olma şansı yoktur.
balıkçılarMar

@Fishinear'ın önerdiği gibi, benzer bir şey kullanmak daha iyidir isRetina = [UIScreen mainScreen].scale > 1.95. Bu ayrıca @ 4x geldiğinde esnek olma avantajına da sahip olacak :)
Danyal Aytekin

Kesinlikle katılmıyorum. Gerekli olmadığında bunu yapmak kodu daha az okunabilir hale getirir. Geleceğin kanıtı açısından geçerliliği olabilir, ancak yakında 4x ekrana sahip olacağımızdan şüpheliyim (eğer varsa).
Ricardo Sanchez-Saez

Yanlış. "donanım tanımlı" olduğu için, hiçbir şekilde bir kayan nokta karşılaştırma sorununu önleyeceğiniz anlamına gelmez. (Bu sadece diğerleri gibi bir şamandıradır.) Herhangi bir şamandırada olduğu gibi, genel olarak asla == kullanamazsınız,> veya <karşılaştırması kullanmalısınız. Kesin> 1.5 hakkında.
Fattie

2

Bu Matt MC'nin yukarıdaki cevabı için bir riff. Sadece bir kategori 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
Önbelleğe almanın alreadyCheckedzahmetli olduğundan şüpheleniyorum , ama iyi.
Dan Rosenstark

@NikolayShubenkov bu yüzden en son kontrol ettim. En kötü senaryoda, fazladan bir veya iki kez kontrol etmek için kodu çalıştırırsınız.
Dan Rosenstark

Diğer bir deyişle şu anda bu değer uygulaması okurken bir işlem zaten kontrol etmeye çalışacağız Yani çökebilir. Bu satırı eklerdim: @synchronyze (zatenChecked) {zatenChecked = EVET}
Nikolay Shubenkov

2

Yukarıdaki cevapların hızlı sürümü> = 2.0 ölçeği ile iPhone 6+ ve Retina'dan daha yüksek ölçeğe sahip diğer gelecekteki cihazları içerir:

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

1

Sadece @sickp'in cevabını ve @ n13'ten gelen yorumu birleştirmek için bunu güzel çalışıyor gibi görünen bir UIScreen kategorisine dönüştürdüm. Kontrol ilk kez aradığınızda yapılır ve daha sonra yapılacak aramalar için kaydedilir.

@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

Birisi için yararlı olabilir.


Önbellek kodu için teşekkürler. Benim tek önerim (Util)bunun yerine (RetinaCheck)... belki daha az net, ama diğer kullanımlara borç vermek. Ayrıca yöntemi adlandıracağımisRetinaDisplay veya başlayan bir şeyi adlandırırdım is, ama belki Obj-C yönergelerini hiç anlamadım. Ayrıca, hayranıyım > 1.0ama ilerlemenin neyin mantıklı olacağını kim bilebilir.
Dan Rosenstark

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;
}

Bence en iyi çözüm.
Nikolay Shubenkov

0

bunu dene

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

En yaygın kullanım durumlarının basitliği için primulaveris'in değiştirilmiş versiyonu. Hızlı 2.2'deyim ama önemli değil.

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
    }
}

O zaman onları böyle kullan

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

0

Bu benim için çalıştı

if((UIScreen .mainScreen().scale) < 2.0)
{
    NSLog("no retina");
}
else
{
    NSLog("retina");
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.