Jak wykryć iPhone'a 5 (urządzenia szerokoekranowe)?


300

Właśnie uaktualniłem do XCode 4.5 GM i odkryłem, że możesz teraz zastosować rozmiar „4” Retina do kontrolera widoku w serii ujęć.

Teraz, jeśli chcę utworzyć aplikację działającą zarówno na iPhonie 4, jak i 5, oczywiście muszę zbudować każde okno dwa razy, ale muszę też sprawdzić, czy użytkownik ma iPhone'a z ekranem 3,5 "lub 4", a następnie zastosować widok.

Jak mam to zrobić?


2
Nie musisz budować każdego „okna” dwa razy. Tylko te, które mają dokładnie pasować do rozmiaru ekranu, będą musiały zostać wyłączone. Rozwiązanie wydaje się dość oczywiste, po prostu sprawdź wymiary okna i dodaj decyzję dotyczącą sprawy na podstawie zwróconego rozmiaru.
Do

1
Cóż, w zasadzie to prawda, ale chcę użyć dodatkowego rozmiaru ekranu w zupełnie inny sposób, tak jak w przypadku ekranu poziomego.
Finn Gaida,


Czy to pytanie powinno zostać zaktualizowane zgodnie z nowymi urządzeniami? Np. „Jak wykryć urządzenie iOS według rozmiaru ekranu”?
hfossli,

Odpowiedzi:


467

Przede wszystkim nie należy odbudowywać wszystkich widoków, aby zmieściły się na nowym ekranie, ani nie używać różnych widoków dla różnych rozmiarów ekranu.

Korzystaj z funkcji automatycznego zmiany rozmiaru systemu iOS, aby Twoje widoki mogły dostosowywać i dostosowywać dowolny rozmiar ekranu.

To nie jest bardzo trudne, przeczytaj dokumentację na ten temat. Zaoszczędzi ci dużo czasu.

iOS 6 oferuje również nowe funkcje w tym zakresie.
Przeczytaj dziennik zmian interfejsu API systemu iOS 6 w witrynie Apple Developer.
I sprawdź nowe możliwości AutoLayout dla iOS 6 .

To powiedziawszy, jeśli naprawdę potrzebujesz wykryć iPhone'a 5, możesz po prostu polegać na rozmiarze ekranu .

[ [ UIScreen mainScreen ] bounds ].size.height

Wysokość ekranu iPhone'a 5 wynosi 568.
Możesz wyobrazić sobie makro, aby uprościć to wszystko:

#define IS_IPHONE_5 ( fabs( ( double )[ [ UIScreen mainScreen ] bounds ].size.height - ( double )568 ) < DBL_EPSILON )

Zastosowanie fabsepsilon ma na celu zapobieganie błędom precyzji podczas porównywania zmiennoprzecinkowych, jak wskazano w komentarzach H2CO3.

Od teraz możesz używać go w standardowych instrukcjach if / else:

if( IS_IPHONE_5 )
{}
else
{}

Edycja - lepsze wykrywanie

Jak twierdzą niektóre osoby, wykrywa to tylko ekran panoramiczny , a nie rzeczywisty iPhone 5.

Kolejne wersje iPoda touch mogą mieć taki ekran, więc możemy użyć innego zestawu makr.

Zmieńmy nazwę oryginalnego makra IS_WIDESCREEN:

#define IS_WIDESCREEN ( fabs( ( double )[ [ UIScreen mainScreen ] bounds ].size.height - ( double )568 ) < DBL_EPSILON )

Dodajmy makra do wykrywania modeli:

#define IS_IPHONE ( [ [ [ UIDevice currentDevice ] model ] isEqualToString: @"iPhone" ] )
#define IS_IPOD   ( [ [ [ UIDevice currentDevice ] model ] isEqualToString: @"iPod touch" ] )

W ten sposób możemy upewnić się, że mamy model iPhone'a ORAZ ekran panoramiczny, i możemy ponownie zdefiniować IS_IPHONE_5makro:

#define IS_IPHONE_5 ( IS_IPHONE && IS_WIDESCREEN )

Należy również pamiętać, że, jak stwierdził @ LearnCocos2D, te makra nie będą działać, jeśli aplikacja nie zostanie zoptymalizowana pod kątem ekranu iPhone'a 5 (brakuje obrazu Default-568h@2x.png), ponieważ rozmiar ekranu nadal będzie wynosił 320 x 480 sprawa.

Nie sądzę, że może to stanowić problem, ponieważ nie rozumiem, dlaczego chcielibyśmy wykryć iPhone'a 5 w niezoptymalizowanej aplikacji.

WAŻNE - obsługa iOS 8

W iOS 8 boundswłaściwość UIScreenklasy odzwierciedla teraz orientację urządzenia .
Tak więc oczywiście poprzedni kod nie zadziała po wyjęciu z pudełka.

Aby to naprawić, możesz po prostu użyć nowej nativeBoundswłaściwości zamiast bounds, ponieważ nie zmieni się ona wraz z orientacją i ponieważ jest oparta na trybie portretowym.
Pamiętaj, że wymiary nativeBoundssą mierzone w pikselach, więc dla iPhone'a 5 wysokość wyniesie 1136 zamiast 568.

Jeśli kierujesz reklamy również na iOS 7 lub niższy, pamiętaj o wykrywaniu funkcji, ponieważ dzwonienie nativeBoundsprzed iOS 8 spowoduje awarię aplikacji:

if( [ [ UIScreen mainScreen ] respondsToSelector: @selector( nativeBounds ) ] )
{
    /* Detect using nativeBounds - iOS 8 and greater */
}
else
{
    /* Detect using bounds - iOS 7 and lower */
}

Możesz dostosować poprzednie makra w następujący sposób:

#define IS_WIDESCREEN_IOS7 ( fabs( ( double )[ [ UIScreen mainScreen ] bounds ].size.height - ( double )568 ) < DBL_EPSILON )
#define IS_WIDESCREEN_IOS8 ( fabs( ( double )[ [ UIScreen mainScreen ] nativeBounds ].size.height - ( double )1136 ) < DBL_EPSILON )
#define IS_WIDESCREEN      ( ( [ [ UIScreen mainScreen ] respondsToSelector: @selector( nativeBounds ) ] ) ? IS_WIDESCREEN_IOS8 : IS_WIDESCREEN_IOS7 )

I oczywiście, jeśli chcesz wykryć iPhone'a 6 lub 6 Plus, użyj odpowiednich rozmiarów ekranu.


7
To źle, będziesz musiał użyć#define IS_IPHONE_5 ( [ [ UIScreen mainScreen ] bounds ].size.height == 568 )
Fabian Kreiser

28
@ H2CO3: Zauważ, że porównanie DBL_EPSILONnie jest tutaj konieczne i że ==porównanie się nie powiedzie: konieczne jest wykonanie porównania z wykorzystaniem różnic w ten sposób, jeśli wartość zmiennoprzecinkowa nie może być wyrażona jako dokładna liczba (jak 1.0/3.0*3.0na przykład). Przeczytaj ten artykuł, aby uzyskać więcej informacji;)
AliSoftware

2
ta odpowiedź jest nieprawidłowa. dlaczego dostał tyle kciuków w górę? nie można użyć tylko wysokości, aby określić, czy jest to ekran panoramiczny. koleś ...
OMGPOP

5
Czy mogę dodać: Jeśli chcesz, aby to działało z symulatorem, użyj tego: # zdefiniuj IS_IPHONE (([[[[[UIDevice currentDevice] model]] isEqualToString: @ "iPhone"]]) || ([[[[[UIDevice currentDevice] model] isEqualToString: @ „iPhone Simulator”]))
David

31
Ta odpowiedź to szaleństwo. Te rzeczy na temat zalecania, aby nie porównywać tego rodzaju pływaków (które w rzeczywistości są - i jeśli wiesz, że Apple powinien wiedzieć, że zawsze będą to - liczby całkowite) z == to nonsens i komplikuje rzeczy. Myślę też, że lepiej jest użyć UI_USER_INTERFACE_IDIOM () do wykrywania iPhone'a, ponieważ działa dobrze zarówno na urządzeniu, jak i na symulatorze (i może być szybszy niż podejście UIDevice). To po prostu działa dobrze i jest o wiele prostszy do odczytania: # zdefiniować IS_IPHONE5 (UI_USER_INTERFACE_IDIOM () == UIUserInterfaceIdiomPhone && [UIScreen mainScreen] .bounds.size.height == 568)
Ricardo Sanchez-Saez

232

Testowane i zaprojektowane pod kątem dowolnej kombinacji zestawu SDK i systemu operacyjnego:

Szybki

Dodano typy iPadów. iPad 2 i iPad mini to iPady bez siatkówki. Podczas gdy iPad Mini 2 i nowszy, iPad 3, 4, iPad Air, Air 2, Air 3 i iPad Pro 9.7 mają tę samą logiczną rozdzielczość 1024. iPad Pro ma maksymalną długość 1366. Odniesienie

import UIKit

public enum DisplayType {
    case unknown
    case iphone4
    case iphone5
    case iphone6
    case iphone6plus
    case iPadNonRetina
    case iPad
    case iPadProBig
    static let iphone7 = iphone6
    static let iphone7plus = iphone6plus
}

public final class Display {
    class var width:CGFloat { return UIScreen.main.bounds.size.width }
    class var height:CGFloat { return UIScreen.main.bounds.size.height }
    class var maxLength:CGFloat { return max(width, height) }
    class var minLength:CGFloat { return min(width, height) }
    class var zoomed:Bool { return UIScreen.main.nativeScale >= UIScreen.main.scale }
    class var retina:Bool { return UIScreen.main.scale >= 2.0 }
    class var phone:Bool { return UIDevice.current.userInterfaceIdiom == .phone }
    class var pad:Bool { return UIDevice.current.userInterfaceIdiom == .pad }
    class var carplay:Bool { return UIDevice.current.userInterfaceIdiom == .carPlay }
    class var tv:Bool { return UIDevice.current.userInterfaceIdiom == .tv }
    class var typeIsLike:DisplayType {
        if phone && maxLength < 568 {
            return .iphone4
        }
        else if phone && maxLength == 568 {
                return .iphone5
        }
        else if phone && maxLength == 667 {
            return .iphone6
        }
        else if phone && maxLength == 736 {
            return .iphone6plus
        }
        else if pad && !retina {
            return .iPadNonRetina
        }
        else if pad && retina && maxLength == 1024 {
            return .iPad
        }
        else if pad && maxLength == 1366 {
            return .iPadProBig
        }
        return .unknown
    }
}

Zobacz to w akcji https://gist.github.com/hfossli/bc93d924649de881ee2882457f14e346

Uwaga: Jeśli np. IPhone 6 jest w trybie powiększenia, interfejs użytkownika jest powiększoną wersją iPhone'a 5. Te funkcje nie określają typu urządzenia, ale tryb wyświetlania, dlatego iPhone 5 jest pożądanym wynikiem w tym przykładzie.

Cel C

#define IS_IPAD (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
#define IS_IPHONE (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
#define IS_RETINA ([[UIScreen mainScreen] scale] >= 2.0)

#define SCREEN_WIDTH ([[UIScreen mainScreen] bounds].size.width)
#define SCREEN_HEIGHT ([[UIScreen mainScreen] bounds].size.height)
#define SCREEN_MAX_LENGTH (MAX(SCREEN_WIDTH, SCREEN_HEIGHT))
#define SCREEN_MIN_LENGTH (MIN(SCREEN_WIDTH, SCREEN_HEIGHT))
#define IS_ZOOMED (IS_IPHONE && SCREEN_MAX_LENGTH == 736.0)

#define IS_IPHONE_4_OR_LESS (IS_IPHONE && SCREEN_MAX_LENGTH < 568.0)
#define IS_IPHONE_5 (IS_IPHONE && SCREEN_MAX_LENGTH == 568.0)
#define IS_IPHONE_6 (IS_IPHONE && SCREEN_MAX_LENGTH == 667.0)
#define IS_IPHONE_6P (IS_IPHONE && SCREEN_MAX_LENGTH == 736.0)

Zastosowanie: http://pastie.org/9687735

Uwaga: Jeśli np. IPhone 6 jest w trybie powiększenia, interfejs użytkownika jest powiększoną wersją iPhone'a 5. Te funkcje nie określają typu urządzenia, ale tryb wyświetlania, dlatego iPhone 5 jest pożądanym wynikiem w tym przykładzie.


1
iPhone 5 zgłosi normalny rozmiar ekranu 480 x 320 bez nowego domyślnego obrazu. Dla mnie jest to pożądane zachowanie.
hfossli,

3
Prawdopodobnie przydatnym dodatkiem jest #define IS_RETINA ([[UIScreen mainScreen] scale] == 2.0)określenie różnicy między iPhone4 i iPhone5 a iPad Retina i non-retina
bshirley

1
Nie zgadzam się. Myślę, że terminologia „panoramiczna” powinna zostać pominięta, ponieważ szybko się zdezaktualizowała.
hfossli

1
@Dvole tak zachowuje się iOS 8. Użyj, SCREEN_MAX_LENGTHaby uzyskać 568 we wszystkich obrotach na iPhonie 5.
hfossli

1
@MattParkins Proponuję przy użyciu bardziej solidne kontrole modelowe stackoverflow.com/questions/13366976/... .
hfossli

69

Naprawdę proste rozwiązanie

if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
{
    CGSize result = [[UIScreen mainScreen] bounds].size;
    if(result.height == 480)
    {
        // iPhone Classic
    }
    if(result.height == 568)
    {
        // iPhone 5
    }
}

1
haha short i simpel, zrobili to samo :) dudnienie za utrzymanie niskiego nad głową! umieszczenie rzeczy w makrze nie jest wyzwaniem ...
benjamin.ludwig

2
Cóż, nie umieszczanie rzeczy w makro lub funkcjach jest podatne na osuszanie ... Od momentu, kiedy musisz to zrobić więcej niż raz ...
hfossli

Tak, ale zdefiniuj makro jak pokazano powyżej, jest wygodniejsze i łatwiejsze, nie musisz wklejać, pisz to, jeśli ... za każdym razem.
Resty

Dzięki, Uratowałeś mi życie: D, ale nie wiem, dlaczego Makro: # zdefiniować IS_IPHONE_5 (IS_IPHONE && [[UIScreen mainScreen] graniczy] .size.height == 568.0) ==> Nie działa w symulatorze iOS 7.1 wcześniej że wciąż pracuję nad XCode 4.6. OMG iOS 7.1 i Xcode 5
Linh Nguyen

zaktualizowana odpowiedź poniżej w celu uwzględnienia iPhone'a 6 i 6 oraz rozmiarów ekranu
Sam B,

28

Teraz musimy uwzględnić rozmiary ekranów iPhone'a 6 i 6Plus. Oto zaktualizowana odpowiedź

if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
{
    //its iPhone. Find out which one?

    CGSize result = [[UIScreen mainScreen] bounds].size;
    if(result.height == 480)
    {
        // iPhone Classic
    }
    else if(result.height == 568)
    {
        // iPhone 5
    }
    else if(result.height == 667)
    {
        // iPhone 6
    }
   else if(result.height == 736)
    {
        // iPhone 6 Plus
    }
}
else
{
     //its iPad
}

Kilka przydatnych informacji

iPhone 6 Plus   736x414 points  2208x1242 pixels    3x scale    1920x1080 physical pixels   401 physical ppi    5.5"
iPhone 6        667x375 points  1334x750 pixels     2x scale    1334x750 physical pixels    326 physical ppi    4.7"
iPhone 5        568x320 points  1136x640 pixels     2x scale    1136x640 physical pixels    326 physical ppi    4.0"
iPhone 4        480x320 points  960x640 pixels      2x scale    960x640 physical pixels     326 physical ppi    3.5"
iPhone 3GS      480x320 points  480x320 pixels      1x scale    480x320 physical pixels     163 physical ppi    3.5"

to po prostu nie działa dla mnie iPhone 5 zdecydował, jak 4 iPhone 6+ w ogóle nie zdecydował Oh mam to jestem w krajobrazie powinienem zmienić wysokość z szerokością :)
ColdSteel

jeśli aplikacja jest w trybie poziomym, upewnij się, że zmieniłeś wynik. wysokość na wynik. szerokość
Sam B

hmm .. na iPhonie 4 (iOS 6.0) nie zamieniło się :( może to być iOS 6.0 prob lub iPhone 4?
ColdSteel

Dobra sprawdziłem zamieniony widok tylko w iOS 8 i nowszych
ColdSteel

iPhone 6 daje wysokość = 568
MaxEcho

15

Wziąłem wolność umieścić makro przez Macmade do funkcji C, i nazwać go poprawnie, ponieważ wykrywa panoramiczny dostępności i nie koniecznie iPhone 5.

Makro również nie wykrywa działania na iPhonie 5 w przypadku, gdy projekt nie zawiera Default-568h@2x.png . Bez nowego domyślnego obrazu iPhone 5 będzie zgłaszał normalny rozmiar ekranu 480 x 320 (w punktach). Zatem sprawdzenie nie dotyczy tylko dostępności ekranu panoramicznego, ale także włączenia trybu panoramicznego .

BOOL isWidescreenEnabled()
{
    return (BOOL)(fabs((double)[UIScreen mainScreen].bounds.size.height - 
                                               (double)568) < DBL_EPSILON);
}

Nadal wolę makra ze względu na wydajność. Proszę zobaczyć edycję mojej odpowiedzi. Sprawdza również model.
Macmade

1
Masz również rację mówiąc, że iPhone 5 będzie zgłaszał normalny rozmiar ekranu 480 x 320 bez nowego domyślnego obrazu. Ale myślę, że nie ma sensu wykrywać iPhone'a 5 w niezoptymalizowanej aplikacji. :)
Macmade

@Macmade Rzeczywiście, nie ma sensu, ale warto pamiętać o tym, że wykrywanie nie działa. Funkcje mogą być również inlined. Zostaną również wstawione tam, gdzie optymalizator kompilatora uważa, że ​​to dobry pomysł i gdzie może wiedzieć, że jest to dozwolone (np. Funkcja jest w tym samym module). Implementacja takich rzeczy za pomocą funkcji może czasem przynieść dodatkowe sprawdzanie typu.
Ivan Vučica

4
Pytanie związane z wydajnością brzmi: dlaczego miałbyś przeprowadzać to sprawdzanie tysiące razy podczas pętli renderowania? W przeciwnym razie wydajność nie jest problemem i jest klarowna i pozwala uniknąć skutków ubocznych o większym znaczeniu.
LearnCocos2D,

Dałem ci za to +1, ponieważ podoba mi się osobna funkcja zamiast makra, ale muszę zaznaczyć, że nie jest tak naprawdę poprawna ani kompletna. Aby wykryć ekran panoramiczny, nie patrz na wysokość ekranu. Zamiast tego spójrz na proporcje i zwróć wartość true tylko wtedy, gdy proporcje są większe lub równe 16: 9.
Todd Lehman

11

Oto nasze kody, test zdany na ios7 / ios8 dla iphone4, iphone5, ipad, iphone6, iphone6p, bez względu na urządzenia lub symulator:

#define IS_IPAD (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
#define IS_IPHONE (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) // iPhone and       iPod touch style UI

#define IS_IPHONE_5_IOS7 (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 568.0f)
#define IS_IPHONE_6_IOS7 (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 667.0f)
#define IS_IPHONE_6P_IOS7 (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 736.0f)
#define IS_IPHONE_4_AND_OLDER_IOS7 (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height < 568.0f)

#define IS_IPHONE_5_IOS8 (IS_IPHONE && ([[UIScreen mainScreen] nativeBounds].size.height/[[UIScreen mainScreen] nativeScale]) == 568.0f)
#define IS_IPHONE_6_IOS8 (IS_IPHONE && ([[UIScreen mainScreen] nativeBounds].size.height/[[UIScreen mainScreen] nativeScale]) == 667.0f)
#define IS_IPHONE_6P_IOS8 (IS_IPHONE && ([[UIScreen mainScreen] nativeBounds].size.height/[[UIScreen mainScreen] nativeScale]) == 736.0f)
#define IS_IPHONE_4_AND_OLDER_IOS8 (IS_IPHONE && ([[UIScreen mainScreen] nativeBounds].size.height/[[UIScreen mainScreen] nativeScale]) < 568.0f)

#define IS_IPHONE_5 ( ( [ [ UIScreen mainScreen ] respondsToSelector: @selector( nativeBounds ) ] ) ? IS_IPHONE_5_IOS8 : IS_IPHONE_5_IOS7 )
#define IS_IPHONE_6 ( ( [ [ UIScreen mainScreen ] respondsToSelector: @selector( nativeBounds ) ] ) ? IS_IPHONE_6_IOS8 : IS_IPHONE_6_IOS7 )
#define IS_IPHONE_6P ( ( [ [ UIScreen mainScreen ] respondsToSelector: @selector( nativeBounds ) ] ) ? IS_IPHONE_6P_IOS8 : IS_IPHONE_6P_IOS7 )
#define IS_IPHONE_4_AND_OLDER ( ( [ [ UIScreen mainScreen ] respondsToSelector: @selector( nativeBounds ) ] ) ? IS_IPHONE_4_AND_OLDER_IOS8 : IS_IPHONE_4_AND_OLDER_IOS7 )

Testuję na iPhonie 6P i moje zdanie jest zgodne z warunkiem IS_IPHONE_5? Jak to możliwe, że Twój kod wygląda dobrze? Zrobiłem prostą kopię i wkleiłem z prostym if / else i wiem, że mój telefon ma 6 plus z systemem iOS 8.3.
Whyoz

7

Użyłem odpowiedzi hfossli i przetłumaczyłem ją na Swift

let IS_IPAD = UIDevice.currentDevice().userInterfaceIdiom == .Pad
let IS_IPHONE = UIDevice.currentDevice().userInterfaceIdiom == .Phone
let IS_RETINA = UIScreen.mainScreen().scale >= 2.0

let SCREEN_WIDTH = UIScreen.mainScreen().bounds.size.width
let SCREEN_HEIGHT = UIScreen.mainScreen().bounds.size.height
let SCREEN_MAX_LENGTH = max(SCREEN_WIDTH, SCREEN_HEIGHT)
let SCREEN_MIN_LENGTH = min(SCREEN_WIDTH, SCREEN_HEIGHT)

let IS_IPHONE_4_OR_LESS = (IS_IPHONE && SCREEN_MAX_LENGTH < 568.0)
let IS_IPHONE_5 = (IS_IPHONE && SCREEN_MAX_LENGTH == 568.0)
let IS_IPHONE_6 = (IS_IPHONE && SCREEN_MAX_LENGTH == 667.0)
let IS_IPHONE_6P = (IS_IPHONE && SCREEN_MAX_LENGTH == 736.0)

6

to jest makro dla mojego projektu cocos2d. powinny być takie same dla innych aplikacji.

#define WIDTH_IPAD 1024
#define WIDTH_IPHONE_5 568
#define WIDTH_IPHONE_4 480
#define HEIGHT_IPAD 768
#define HEIGHT_IPHONE 320

#define IS_IPHONE (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
#define IS_IPAD (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)

//width is height!
#define IS_IPHONE_5 ( [ [ UIScreen mainScreen ] bounds ].size.height == WIDTH_IPHONE_5 )
#define IS_IPHONE_4 ( [ [ UIScreen mainScreen ] bounds ].size.height == WIDTH_IPHONE_4 )

#define cp_ph4(__X__, __Y__) ccp(cx_ph4(__X__), cy_ph4(__Y__))
#define cx_ph4(__X__) (IS_IPAD ? (__X__ * WIDTH_IPAD / WIDTH_IPHONE_4) : (IS_IPHONE_5 ? (__X__ * WIDTH_IPHONE_5 / WIDTH_IPHONE_4) : (__X__)))
#define cy_ph4(__Y__) (IS_IPAD ? (__Y__ * HEIGHT_IPAD / HEIGHT_IPHONE) : (__Y__))

#define cp_pad(__X__, __Y__) ccp(cx_pad(__X__), cy_pad(__Y__))
#define cx_pad(__X__) (IS_IPAD ? (__X__) : (IS_IPHONE_5 ? (__X__ * WIDTH_IPHONE_5 / WIDTH_IPAD) : (__X__ * WIDTH_IPHONE_4 / WIDTH_IPAD)))
#define cy_pad(__Y__) (IS_IPAD ? (__Y__) : (__Y__ * HEIGHT_IPHONE / HEIGHT_IPAD))

5
if ((int)[[UIScreen mainScreen] bounds].size.height == 568)
{
    // This is iPhone 5 screen
} else {
    // This is iPhone 4 screen
}

3

W projekcie Swift, iOS 8+ lubię tworzyć rozszerzenia UIScreen, takie jak:

extension UIScreen {

    var isPhone4: Bool {
        return self.nativeBounds.size.height == 960;
    }

    var isPhone5: Bool {
        return self.nativeBounds.size.height == 1136;
    }

    var isPhone6: Bool {
        return self.nativeBounds.size.height == 1334;
    }

    var isPhone6Plus: Bool {
        return self.nativeBounds.size.height == 2208;
    }

}

(UWAGA: nativeBoundsjest w pikselach).

A wtedy kod będzie wyglądał następująco:

if UIScreen.mainScreen().isPhone4 {
    // do smth on the smallest screen
}

Dlatego kod wyjaśnia, że ​​jest to sprawdzenie ekranu głównego, a nie modelu urządzenia.


2

Pożyczając od odpowiedzi Samrata Mazumdara, oto krótka metoda, która szacuje rozmiar ekranu urządzenia. Działa z najnowszymi urządzeniami, ale może nie działać na przyszłych (jak wszystkie metody zgadywania). Zostanie również zdezorientowany, jeśli urządzenie jest dublowane (zwraca rozmiar ekranu urządzenia, a nie rozmiar ekranu dublowanego)

#define SCREEN_SIZE_IPHONE_CLASSIC 3.5
#define SCREEN_SIZE_IPHONE_TALL 4.0
#define SCREEN_SIZE_IPAD_CLASSIC 9.7

+ (CGFloat)screenPhysicalSize
{
    if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
    {
        CGSize result = [[UIScreen mainScreen] bounds].size;
        if (result.height < 500)
            return SCREEN_SIZE_IPHONE_CLASSIC;  // iPhone 4S / 4th Gen iPod Touch or earlier
        else
            return SCREEN_SIZE_IPHONE_TALL;  // iPhone 5
    }
    else
    {
        return SCREEN_SIZE_IPAD_CLASSIC; // iPad
    }
} 

Potrzebuje rewizji dla iPada mini, ale nie sądzę, że będziesz w stanie ustalić w tej rezydencji.
Daniel

Tak, iPad mini ma tę samą rozdzielczość co iPad2, więc ta metoda nie działa. Nie jestem pewien, jak teraz poradzić sobie z tą sprawą ...
Jeff Hay,

1
Nie powinieneś. Możesz sprawdzić identyfikator urządzenia dla „iPada 2,5”. Kup także musisz sprawdzić 2,6 i 2,7 - tylko wersja Wi-Fi, GSM i CDMA. Ale to oznacza, że ​​następny iPad mini zostanie wydany i będziesz musiał zaktualizować kod na te identyfikatory, których nie znasz wcześniej. Nie możesz ciągle wiedzieć, kiedy jesteś na iPadzie mini, ponieważ tak naprawdę nie powinieneś próbować „optymalizować” na mniejszym ekranie
Daniel

2

Myślę, że dobrze by było, gdyby to makro działało w urządzeniu i symulatorze, poniżej znajduje się rozwiązanie.

#define IS_WIDESCREEN (fabs((double)[[UIScreen mainScreen]bounds].size.height - (double)568) < DBL_EPSILON)
#define IS_IPHONE (([[[UIDevice currentDevice] model] isEqualToString:@"iPhone"]) || ([[[UIDevice currentDevice] model] isEqualToString: @"iPhone Simulator"]))
#define IS_IPOD   ([[[UIDevice currentDevice]model] isEqualToString:@"iPod touch"])
#define IS_IPHONE_5 ((IS_IPHONE || IS_IPOD) && IS_WIDESCREEN)

2

Odkryłem, że odpowiedzi nie obejmują specjalnego przypadku dla symulatorów.

#define IS_WIDESCREEN ( [ [ UIScreen mainScreen ] bounds ].size.height == 568  )
#define IS_IPHONE ([[ [ UIDevice currentDevice ] model ] rangeOfString:@"iPhone"].location != NSNotFound)
#define IS_IPAD ([[ [ UIDevice currentDevice ] model ] rangeOfString:@"iPad"].location != NSNotFound)
#define IS_IPHONE_5 ( IS_IPHONE && IS_WIDESCREEN )

2
+(BOOL)isDeviceiPhone5
{
    BOOL iPhone5 = FALSE;

    CGRect screenBounds = [[UIScreen mainScreen] bounds];
    if (screenBounds.size.height == 568)
    {
        // code for 4-inch screen
        iPhone5 = TRUE;
    }
    else
    {
        iPhone5 = FALSE;
        // code for 3.5-inch screen
    }
    return iPhone5;

}

iPhone5 = FALSE;jest niepotrzebne, ponieważ zmienna ma już tę wartość, jeśli się nie zmieni
mcont

1
CGFloat height = [UIScreen mainScreen].bounds.size.height;

NSLog(@"screen soze is %f",height);

  if (height>550) {

          // 4" screen-do some thing
     }

  else if (height<500) {

        // 3.5 " screen- do some thing

     }


1

W ten sposób możesz wykryć rodzinę urządzeń.

    #import <sys/utsname.h>
    NSString* deviceName()
    {
        struct utsname systemInformation;
        uname(&systemInformation);
        NSString *result = [NSString stringWithCString:systemInformation.machine
                                              encoding:NSUTF8StringEncoding];
        return result;
    }

    #define isIPhone5  [deviceName() rangeOfString:@"iPhone5,"].location != NSNotFound
    #define isIPhone5S [deviceName() rangeOfString:@"iPhone6,"].location != NSNotFound

1

Jeśli projekt został utworzony przy użyciu Xcode 6, użyj poniższego kodu do wykrycia urządzeń.

printf("\nDetected Resolution : %d x %d\n\n",(int)[[UIScreen mainScreen] nativeBounds].size.width,(int)[[UIScreen mainScreen] nativeBounds].size.height);

if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone){
    if ([[UIScreen mainScreen] respondsToSelector: @selector(scale)])
    {
        if([[UIScreen mainScreen] nativeBounds].size.height == 960 || [[UIScreen mainScreen] nativeBounds].size.height == 480){
            printf("Device Type : iPhone 4,4s ");

        }else if([[UIScreen mainScreen] nativeBounds].size.height == 1136){
            printf("Device Type : iPhone 5,5S/iPod 5 ");

        }else if([[UIScreen mainScreen] nativeBounds].size.height == 1334){
            printf("Device Type : iPhone 6 ");

        }else if([[UIScreen mainScreen] nativeBounds].size.height == 2208){
            printf("Device Type : iPhone 6+ ");

        }
    }
}else{
    printf("Device Type : iPad");
}

Jeśli projekt został utworzony w Xcode 5 i otwarty w Xcode 6, użyj poniższego kodu do wykrycia urządzeń (ten kod działa, jeśli nie są przypisane żadne obrazy uruchamiania dla iPhone'a 6,6+)

printf("\nDetected Resolution : %d x %d\n\n",(int)[[UIScreen mainScreen] nativeBounds].size.width,(int)[[UIScreen mainScreen] nativeBounds].size.height);
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone){
    if ([[UIScreen mainScreen] respondsToSelector: @selector(scale)])
    {
       if([[UIScreen mainScreen] nativeBounds].size.height == 960 || [[UIScreen mainScreen] nativeBounds].size.height == 480){
            printf("Device Type : iPhone 4,4s");
            appType=1;
        }else if([[UIScreen mainScreen] nativeBounds].size.height == 1136 || [[UIScreen mainScreen] nativeBounds].size.height == 1704){
            printf("Device Type : iPhone 5,5S,6,6S/iPod 5 ");
            appType=3;
        }
    }
}else{
    printf("Device Type : iPad");
    appType=2;
}

Jeśli nadal używasz Xcode 5 razem, użyj następującego kodu do wykrycia urządzeń (iPhone 6 i 6+ nie zostaną wykryte)

printf("\nDetected Resolution : %d x %d\n\n",(int)[[UIScreen mainScreen] bounds].size.width,(int)[[UIScreen mainScreen] bounds].size.height);
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone){
    if ([[UIScreen mainScreen] respondsToSelector: @selector(scale)])
    {
        CGSize result = [[UIScreen mainScreen] bounds].size;
        CGFloat scale = [UIScreen mainScreen].scale;
        result = CGSizeMake(result.width * scale, result.height * scale);
        if(result.height == 960 || result.height == 480){
            printf("Device Type : iPhone 4,4S ");

        }else if(result.height == 1136){
            printf("Device Type : iPhone 5s/iPod 5");

        }
    }
}else{
    printf("Device Type : iPad");

}

1
  1. Dodaj „Nowy plik Swift” -> AppDelegateEx.swift

  2. dodaj rozszerzenie do AppDelegate

    import UIKit
    extension AppDelegate {
         class func isIPhone5 () -> Bool{
             return max(UIScreen.mainScreen().bounds.width, UIScreen.mainScreen().bounds.height) == 568.0
        }
        class func isIPhone6 () -> Bool {
            return max(UIScreen.mainScreen().bounds.width, UIScreen.mainScreen().bounds.height) == 667.0
        }
        class func isIPhone6Plus () -> Bool {
            return max(UIScreen.mainScreen().bounds.width, UIScreen.mainScreen().bounds.height) == 736.0
        }  
    }
  3. stosowanie:

        if AppDelegate.isIPhone5() {
            collectionViewTopConstraint.constant = 2
        }else if AppDelegate.isIPhone6() {
            collectionViewTopConstraint.constant = 20
        }

1

W Swift 3 możesz użyć mojej prostej klasy KRDeviceType.

https://github.com/ulian-onua/KRDeviceType

Jest dobrze udokumentowany i obsługuje operatorów ==,> =, <=.

Na przykład, aby wykryć, czy urządzenie ma ograniczenia iPhone'a 6 / 6s / 7, możesz po prostu użyć następnego porównania:

if KRDeviceType() == .iPhone6 {
// Perform appropiate operations
}

Aby wykryć, czy urządzenie ma ograniczenia iPhone'a 5 / 5S / SE lub starszego (iPhone 4s), możesz użyć następnego porównania:

if KRDeviceType() <= .iPhone5 {   //iPhone 5/5s/SE of iPhone 4s
// Perform appropiate operations (for example, set up constraints for those old devices)
}

1

Odpowiedziano na to sto razy, ale to rozwiązanie działało dla mnie najlepiej i pomogło rozwiązać problem, gdy wprowadzane są nowe urządzenia i nie mam zdefiniowanego rozmiaru.

Swift 5 Helper:

extension UIScreen {
    func phoneSizeInInches() -> CGFloat {
        switch (self.nativeBounds.size.height) {
        case 960, 480:
            return 3.5  //iPhone 4
        case 1136:
            return 4    //iPhone 5
        case 1334:
            return 4.7  //iPhone 6
        case 2208:
            return 5.5  //iPhone 6 Plus
        case 2436:
            return 5.8  //iPhone X
        case 1792:
            return 5.5  //iPhone XR
        case 2688:
            return 6.5  //iPhone XS Max
        default:
            let scale = self.scale
            let ppi = scale * 163
            let width = self.bounds.size.width * scale
            let height = self.bounds.size.height * scale
            let horizontal = width / ppi, vertical = height / ppi
            let diagonal = sqrt(pow(horizontal, 2) + pow(vertical, 2))
            return diagonal
        }
    }
}

Wynika to z faktu, że łatwo jest zapamiętać rozmiary cali telefonu, takie jak urządzenie „5,5 cala” lub „4,7 cala”, ale trudno jest zapamiętać dokładne rozmiary pikseli.

if UIScreen.main.phoneSizeInInches() == 4 {
  //do something with only 4 inch iPhones
}

Daje to również możliwość zrobienia czegoś takiego:

if UIScreen.main.phoneSizeInInches() < 5.5 {
  //do something all iPhones smaller than the plus
}

Domyślnie: próbuje zastosowań rozmiar ekranu i skalę, aby spróbować i obliczyć cali przekątnej. Dzieje się tak w przypadku, gdy pojawi się nowy rozmiar urządzenia, postaramy się jak najlepiej ustalić, a kod, taki jak ostatni przykład, powinien nadal działać.


0

użyj następującego kodu:

CGFloat screenScale = [[UIScreen mainScreen] scale];

CGRect screenBounds = [[UIScreen mainScreen] bounds]; 

CGSize screenSize = CGSizeMake(screenBounds.size.width * screenScale, screenBounds.size.height * screenScale); 

if (screenSize.height==1136.000000)
{ 
    // Here iPhone 5 View

    // Eg: Nextview~iPhone5.Xib
} else {
   // Previous Phones 

   // Eg : Nextview.xib
}

0

Oto poprawny test urządzenia, bez względu na orientację

- (BOOL)isIPhone5
{
    CGSize size = [[UIScreen mainScreen] bounds].size;
    if (MIN(size.width,size.height) == 320 && MAX(size.width,size.height == 568)) {
        return YES;
    }
    return NO;
}

-2

Służy do wykrywania urządzeń iPhone i iPad wszystkich wersji.

#define IS_IPAD (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
#define IS_IPHONE (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
#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_6_PLUS (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 736.0)
#define IS_RETINA ([[UIScreen mainScreen] scale] == 2.0) 

iPhone 6 nie ma wyświetlacza Retina?
vikingosegundo

iPhone6 ​​ma wyświetlacz ratina (@ 2X). a iPhone6 ​​plus ma wyświetlacz HD (@ 3X).
Vaibhav Sharma

Więc jeśli testowany IS_RETINAna iPhone 6 plus, wykonywany jest kod 1x?
vikingosegundo


1
nie rozumiesz tego: twoje reguły ustąpią @1xtam, gdzie powinny @3x. w każdym razie: jak tylko kopiujesz i
wklejasz
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.