망막 디스플레이 감지


223

iOS SDK는 currentDevice에 고해상도 디스플레이 (망막)가 있는지 쉽게 확인할 수있는 방법을 제공합니까?

내가 지금 찾은 가장 좋은 방법은 다음과 같습니다.

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

호기심에서-더 큰 버전의 예술 작품을 보여주는 것 이외의 디스플레이를 감지 할 때 무엇을하고 있습니까?
Michael Behan


@ mbehan : TTImageView (Three20 프레임 워크 참조)가 있고 이미지의 고해상도 URL을 제공하고 싶습니다.
Pierre Valade

1
이 질문은 4 가지 디스플레이 크기 모두에 사용할 수있는 UI로 제공되는 이미지를 다운로드했으며 사용자에게 적절한 이미지 만 다운로드하도록 해주기 때문에 유용합니다.
페드로

@ mbehan : 제 경우에는 망막 화면과 비 망막 화면 모두에서 1px 인 사용자 지정 셀 구분 기호 (예 : 기본 구분 기호)를 원했습니다. 두께를 1px로 설정하면 망막 디스플레이에서 2px로 렌더링됩니다 (분명히).
user3099609

답변:


295

모든 iOS 기기에서 Retina 디스플레이를 안정적으로 감지하려면 기기에서 iOS4 +가 실행되고 있는지, [UIScreen mainScreen].scale속성이 2.0 인지 확인해야합니다 . scaleiPad 3.2 에도이 속성이 포함되어 있으므로 속성이 존재하는 경우 장치에서 iOS4 +를 실행한다고 가정 할 수 없습니다 .

iOS3.2를 실행하는 iPad의 경우 기기에 Retina 디스플레이가 포함되어 있지 않은 경우에도 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이 iPad 용 iOS4.2에서이 동작을 변경했습니다"라고 말하면, iOS4.1에서는 위의 코드가 2x 모드에서 iPhone 앱을 실행하는 iPad의 경우 "is Retina"를 반환한다는 것을 의미합니다. 내가 잘못?
makdad

9
아이 패드 용 4.1은 없었다. 3.2 만, 4.2 만
Jonny

11
이 호출은 약간 비싸서 앱 시작시 BOOL을 초기화하고 앱에서 사용합니다.
n13

를 사용하여 버전을 확인하는 것을 선호합니다 [UIDevice currentDevice].systemVersion]. 이 경우 NSString *currentSystemVersion = [[UIDevice currentDevice] systemVersion]; return [currentSystemVersion compare:version options:NSNumericSearch];
샌디 채프먼

xcode 4의 비 레티 나 iPad (ios 7.1) 시뮬레이터에서 작동하지 않는 것 같습니다 ... 이상합니다.
Isaac Paul

81

@sickp의 답변이 맞습니다. 작업을 쉽게하기 위해 Shared.pch 파일에 다음 줄을 추가하십시오.

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

그런 다음 모든 파일에서 다음을 수행 할 수 있습니다.

if(IS_RETINA)
{
   // etc..
}

시뮬레이터에서는 작동하지 않습니다. respondsToSelector 때문입니까? 시뮬레이터가 선택기에 응답하지 않습니까?
arniotaki

2
큰! 그러나 iPhone 6 Plus를 고려하려면 크기가 2.0 이상인지 확인해야합니다.
Ivan Carosati

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

23
?1:0? 그것은 표현식의 부울 부분에서 이미 계산 된 것을 반복하지 않습니까?
d11wtq

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
        }

iscreenScale이 2.0이 아닌 3.0 이상인 경우 Swift 5 isRetinaHD에서 작동하도록 업데이트 된 코드가 아니어야합니까 ??? 편집 : 나는 그것을 업데이트 ...
C0D3 14:07에

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, retina iPhone의 경우 1, 표준 해상도 iPad의 경우 2, retina iPad의 경우 3이 반환됩니다.



5

부동 소수점 값이 동일한 지 비교하기에는 항상 약간 불안합니다. 나는 어느 쪽이든가는 것을 선호한다

[UIScreen mainScreen].scale > 1.0;

또는

[UIScreen mainScreen].scale < 2.0;

5
평등을 위해 두 개의 부동 소수점 값을 비교하는 것은 계산 후 정수 값과 약간 다를 수 있기 때문에 "느긋함을 느낀다". 그러나 이러한 상황에서 <또는>와 비교하는 것은 어려운 일입니다. 그러나이 경우 하드웨어 정의이므로 스케일이 정확히 1.0 또는 2.0이 아닐 가능성은 없습니다.
fishinear

@fishinear가 제안했듯이와 같은 것을 사용하는 것이 좋습니다 isRetina = [UIScreen mainScreen].scale > 1.95. 이것은 또한 @ 4x가 올 때 회복력이 있다는 이점을 가질 것입니다 :)
Danyal Aytekin

나는 매우 동의하지 않습니다. 필요하지 않은 경우이 작업을 수행하면 코드를 읽을 수 없게됩니다. 미래 보장에 대한 요점은 타당 할 수 있지만, 조만간 @ 4x 화면이 나올 것입니다.
Ricardo Sanchez-Saez

잘못된. "하드웨어 정의"이기 때문에 플로트 비교 문제를 피할 수는 없습니다. 다른 플로트와 마찬가지로 플로트와 마찬가지로 일반적으로 ==를 사용할 수 없으므로> 또는 <비교를 사용해야합니다. 확실하게 1.5 이상은 어떻습니까?
Fattie

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

@NikolayShubenkov 그래서 내가 이미 마지막으로 설정했습니다. 최악의 시나리오에서는 코드를 실행하여 추가 시간을 확인합니다.
Dan Rosenstark

다른 프로세스가 현재이 값을 읽는 동안 한 프로세스가 이미 확인하려고하면 앱이 중단 될 수 있습니다. @synchronyze (alreadyChecked) {alreadyChecked = YES}
Nikolay Shubenkov 2016

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

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

내가 생각하는 최고의 솔루션.
Nikolay Shubenkov

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의 수정 된 버전입니다. 나는 빠른 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)

0

이것은 나를 위해 일했다

if((UIScreen .mainScreen().scale) < 2.0)
{
    NSLog("no retina");
}
else
{
    NSLog("retina");
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.