Отримання орієнтації пристрою в Swift


79

Мені цікаво, як я можу отримати поточну орієнтацію пристрою в Swift? Я знаю, що є приклади для Objective-C, однак мені не вдалося змусити його працювати в Swift.

Я намагаюся отримати орієнтацію пристрою і ввести це в оператор if.

Це рядок, з яким у мене найбільше проблем:

[[UIApplication sharedApplication] statusBarOrientation]

Та що з тобою таке? Перекласти це на Свіфт або отримати ті очікувані значення?
— Девід Роннквіст,

1
Орієнтація пристрою не обов'язково відповідає орієнтації інтерфейсу користувача. Точка корпусу - ляжте пристрій рівно і протестуйте свій код!
— Патрік

Відповіді:


70

Ви можете використовувати:

override func didRotateFromInterfaceOrientation(fromInterfaceOrientation: UIInterfaceOrientation) {
    var text=""
    switch UIDevice.currentDevice().orientation{
    case .Portrait:
        text="Portrait"
    case .PortraitUpsideDown:
        text="PortraitUpsideDown"
    case .LandscapeLeft:
        text="LandscapeLeft"
    case .LandscapeRight:
        text="LandscapeRight"
    default:
        text="Another"
    }
    NSLog("You have moved: \(text)")        
}

SWIFT 3 ОНОВЛЕННЯ

override func didRotate(from fromInterfaceOrientation: UIInterfaceOrientation) {
    var text=""
    switch UIDevice.current.orientation{
    case .portrait:
        text="Portrait"
    case .portraitUpsideDown:
        text="PortraitUpsideDown"
    case .landscapeLeft:
        text="LandscapeLeft"
    case .landscapeRight:
        text="LandscapeRight"
    default:
        text="Another"
    }
    NSLog("You have moved: \(text)")        
}

або

override func willRotateToInterfaceOrientation(toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval) {
}

за допомогою Notification ви можете перевірити: IOS8 Swift: Як виявити зміну орієнтації?

ПРИМІТКА: didRotateFromInterfaceOrientation застаріле Використовуйте viewWillTransitionToSize для iOS 2.0 та новіших версій

У випадку Face Up та Face Down це не буде працювати. Тому нам потрібно використовувати наступне.

if UIApplication.shared.statusBarOrientation.isLandscape {
     // activate landscape changes
} else {
     // activate portrait changes
}

Дякуємо за ваш спільний доступ!
— ssowri1

Хм ... а що, якби користувач перейшов до цього подання вже після обертання, ми б не знали початкової орієнтації ...
— ScottyBlades

Якщо ви все ще використовуєте цю функцію, незважаючи на те, що вона застаріла. не забудьте назвати це супер методом у вашій реалізації. тобто: super.didRotate(from: fromInterfaceOrientation). З документації Apple: "Ваша реалізація цього методу повинна викликати супер у певний момент під час його виконання".
— Бокаксіка

55

Щоб отримати орієнтацію рядка стану (і відповідно до цього інтерфейсу), як у вас є код Objective-C, це просто:

UIApplication.sharedApplication().statusBarOrientation

Ви також можете використовувати orientationвластивість UIDevice:

UIDevice.currentDevice().orientation

Однак це може не відповідати орієнтації вашого інтерфейсу. З документації:

Значення властивості є константою, яка вказує на поточну орієнтацію пристрою. Це значення відображає фізичну орієнтацію пристрою і може відрізнятися від поточної орієнтації інтерфейсу користувача вашої програми. Опис можливих значень див. У розділі “UIDeviceOrientation”.


UIApplication.sharedApplication (). StatusBarOrientation є лише в основному потоці
— Yair hadad

Дякую за твою допомогу!
— ssowri1

1
Я використовував uidevice.current.orientation.isportrait, щоб перевірити орієнтацію пристрою та змінити інтерфейс користувача програми, але він змінювався, навіть якщо поставити пристрій на стіл. Але завдяки вам зараз він працює нормально
— Галфхам-хан,

оновлено на швидкій версії 5.1 -> UIDevice.current.orientation
— Роналду Альбертіні

UIDevice.current.orientation.isPor Portrait не працює, якщо орієнтація пристрою спрямована догори або донизу. Перевірка рядка стану, як ця відповідь, була послідовною і працюючою для мене.
— Остін,

26

Apple нещодавно позбулася ідеї пейзажу проти портрета і вважає за краще використовувати розмір екрану. Однак це працює:

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
    if UIDevice.currentDevice().orientation.isLandscape.boolValue {
        print("landscape")
    } else {
        print("portrait")
    }
}

7
З вашим рішенням я б зауважив, що apple стверджує: "Якщо ви перевизначите цей метод у своїх користувацьких контролерах подання, завжди телефонуйте супер у якийсь момент вашої реалізації"
— Popmedic

25
struct DeviceInfo {
struct Orientation {
    // indicate current device is in the LandScape orientation
    static var isLandscape: Bool {
        get {
            return UIDevice.current.orientation.isValidInterfaceOrientation
                ? UIDevice.current.orientation.isLandscape
                : UIApplication.shared.statusBarOrientation.isLandscape
        }
    }
    // indicate current device is in the Portrait orientation
    static var isPortrait: Bool {
        get {
            return UIDevice.current.orientation.isValidInterfaceOrientation
                ? UIDevice.current.orientation.isPortrait
                : UIApplication.shared.statusBarOrientation.isPortrait
        }
    }
}}

відповідь swift4: ось як я це роблю,

1. працює для всіх видів контролера перегляду

2. також працювати, коли користувач обертає додаток

3. також вперше встановіть програму


1
ідеальна відповідь! Дякую
— завершіть

Приємно, але чому ви пишете це час буксирування замість класу @objc var isLandscape: Bool {return! IsPor Portrait} Я не отримую чогось вирішального? ;)
— Ренетик

Ого, це чудово працює, як і я не буду .. Щиро дякую :)
— Йогеш Патель

Як я знаю, що орієнтація змінилася?
— Даніель Спрінгер

14

Свіфт 4:

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        if UIDevice.current.orientation.isLandscape {
            print("landscape")
        } else {
            print("portrait")
        }
    }

А як щодо плоскої орієнтації?
— Міхал Зіобро,

2
Не забудьте зателефонувати super.viewWillTransition (до: size, with: координатар) у певний момент у вашій функції заміщення.
— Бокаксіка,

13

Щоб знайти поточну орієнтацію пристрою, просто скористайтеся цим кодом:

UIApplication.sharedApplication (). StatusBarOrientation

для швидкого 3.0

UIApplication.shared.statusBarOrientation


iPad air 1 & 2 повертає неправильне значення, iPad 2 і iPhone правильні. Я справді намагаюся знайти той, який працює на всіх пристроях, але тут яблуко зробило справжню безлад! :(
— Стівен Б.

на відміну від UIDevice.current.orientation, UIApplication.shared.statusBarOrientationдоступний при початковому завантаженні, а не лише після обертання екрана.
— ewizard

10

У мене були проблеми з використанням InterfaceOrientation, це працювало нормально, за винятком того, що він не отримував доступ до орієнтації при завантаженні. Тож я спробував це, і це хранитель. Це спрацьовує, оскільки значення bounds.widthзавжди посилається на поточну орієнтацію, на відміну від nativeBounds.widthякої є абсолютною.

    if UIScreen.mainScreen().bounds.height > UIScreen.mainScreen().bounds.width {
        // do your portrait stuff
    } else {    // in landscape
        // do your landscape stuff
    }

Я називаю це від willRotateToInterfaceOrientation(toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval)і від, viewDidLoadале це гнучко.

Завдяки zSprawl за вказівник у цьому напрямку. Слід зазначити, що це добре лише для iOS 8 і пізніших версій.


НЕ працює на iPad 9 та 10 iPad, лише початкове значення є правильним, усі наступні значення мають протилежну орієнтацію.
— Стівен Б.

@ Steven.B Hmmm ... чудово працює на моєму iPad Air, iPad 3 та симуляторі під iOS 9. Також працював із бета-тестерами. Можливо, ви також використовуєте інший код, який впливає на це.
— bpedit

Цей код, ймовірно, працює лише при використанні в контролері UIView, я намагаюся отримати орієнтацію та межі у власному класі UIView, але майже кожен тестований пристрій повертає різні значення, коли орієнтація правильна, ніж рамка, або межі все ще помиляються.
— Стівен Б.

10

Отже, якщо Apple відмовляється від цілого елемента орієнтаційного рядка ("портрет", "пейзаж"), то все, що вам важливо, - це відношення ширини до висоти. (як-от відповідь @ bpedit)

Коли ви ділите ширину на висоту, якщо результат менше 1, тоді mainScreen або контейнер або що завгодно перебуває у "портретному" "режимі". Якщо результат перевищує 1, це картина "пейзаж". ;)

override func viewWillAppear(animated: Bool) {
    let size: CGSize = UIScreen.mainScreen().bounds.size
    if size.width / size.height > 1 {
        print("landscape")
    } else {
        print("portrait")
    }
}
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
    if size.width / size.height > 1 {
        print("landscape")
    } else {
        print("portrait")
    }
}

(Я здогадуюсь, що якщо ви використовуєте такий підхід, то вам, мабуть, насправді не цікаво конкретно обробляти умову, коли коефіцієнт рівно 1, рівна ширина та висота.)


1
Приємно! Невелике вдосконалення вашої відповіді: Не забудьте зателефонувати super.viewWillAppear(animated)і super.viewWillTransition(to: size, with: coordinator)в якийсь момент у ваших головних функціях
— Бокаксіка

8

Свіфт 3+

В основному:

NotificationCenter.default.addObserver(self, selector: #selector(self.didOrientationChange(_:)), name: .UIDeviceOrientationDidChange, object: nil)

@objc func didOrientationChange(_ notification: Notification) {
    //const_pickerBottom.constant = 394
    print("other")
    switch UIDevice.current.orientation {
        case .landscapeLeft, .landscapeRight:
            print("landscape")
        case .portrait, .portraitUpsideDown:
            print("portrait")
        default:
            print("other")
    }
}

:)


Я люблю цю відповідь. Це дуже корисно для великих екранів, таких як iPad, де ви не можете використовувати, func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?)оскільки колекція ознак буде завжди, width.regularі height.regular, отже, traitCollection не зміниться при обертанні. У Swift 4 повідомлення було перейменовано на UIDevice.orientationDidChangeNotification.
— Бокаксіка,

3

Свіфт 3 , заснований на відповіді Роба

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    if (size.width / size.height > 1) {
        print("landscape")
    } else {
        print("portrait")
    }
}

2
Не забудьте зателефонувати super.viewWillTransition(to: size, with: coordinator)в якийсь момент у вашій
— замінній

3

Я виявив, що альтернативний код у Swift для коду Obj-C

if (UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) 

є

if UIApplication.shared.statusBarOrientation.isLandscape

Примітка: ми намагаємось знайти, щоб орієнтація рядка стану була альбомною чи ні. Якщо це пейзаж, то твердження if відповідає дійсності.


3

statusBarOrientation НЕ рекомендується , тому НЕ більш доступні для використання , як в вищенаведених відповідей

У цьому коді можна отримати орієнтацію, не турбуючись про амортизацію. Swift 5 ioS 13.2 Перевірено на 100%

struct Orientation {
    // indicate current device is in the LandScape orientation
    static var isLandscape: Bool {
        get {
            return UIDevice.current.orientation.isValidInterfaceOrientation
                ? UIDevice.current.orientation.isLandscape
                : (UIApplication.shared.windows.first?.windowScene?.interfaceOrientation.isLandscape)!
        }
    }
    // indicate current device is in the Portrait orientation
    static var isPortrait: Bool {
        get {
            return UIDevice.current.orientation.isValidInterfaceOrientation
                ? UIDevice.current.orientation.isPortrait
                : (UIApplication.shared.windows.first?.windowScene?.interfaceOrientation.isPortrait)!
        }
    }
}

2
   override func willRotateToInterfaceOrientation(toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval) {
    if (toInterfaceOrientation.isLandscape) {
        NSLog("Landscape");
    }
    else {
        NSLog("Portrait");
    }
}

0

Спробуйте використовувати horizontalSizeClass& verticalSizeClass:

import SwiftUI

struct DemoView: View {
    
    @Environment(\.horizontalSizeClass) var hSizeClass
    @Environment(\.verticalSizeClass) var vSizeClass
    
    var body: some View {
        VStack {
            if hSizeClass == .compact && vSizeClass == .regular {
                VStack {
                    Text("Vertical View")
                }
            } else {
                HStack {
                    Text("Horizontal View")
                }
            }
        }
    }
}

Знайшов це в цьому посібнику . Пов’язана документація Apple .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.