Я хочу добавить два изображения в одно изображение (т.е. для одного изображения в альбомной ориентации и другого для портретного изображения), но я не знаю, как определять изменения ориентации с помощью быстрых языков.
Я пробовал этот ответ, но требуется только одно изображение
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
if UIDevice.currentDevice().orientation.isLandscape.boolValue {
print("Landscape")
} else {
print("Portrait")
}
}
Я новичок в разработке iOS, буду благодарен за любой совет!
Ответы:
let const = "Background" //image name let const2 = "GreyBackground" // image name @IBOutlet weak var imageView: UIImageView! override func viewDidLoad() { super.viewDidLoad() imageView.image = UIImage(named: const) // Do any additional setup after loading the view. } override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) if UIDevice.current.orientation.isLandscape { print("Landscape") imageView.image = UIImage(named: const2) } else { print("Portrait") imageView.image = UIImage(named: const) } }
источник
viewWillTransition
при создании подклассовUIView
?.isFlat
. Если вы хотите только поймать,portrait
я предлагаю вам изменить предложение else наelse if UIDevice.current.orientation.isPortrait
. Примечание:.isFlat
может происходить как в портретной, так и в альбомной ориентации, и только с помощью else {} он будет использоваться по умолчанию всегда (даже если это плоский пейзаж).Использование NotificationCenter и UIDevice «S
beginGeneratingDeviceOrientationNotifications
Swift 4.2+
override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver(self, selector: #selector(ViewController.rotated), name: UIDevice.orientationDidChangeNotification, object: nil) } deinit { NotificationCenter.default.removeObserver(self, name: UIDevice.orientationDidChangeNotification, object: nil) } func rotated() { if UIDevice.current.orientation.isLandscape { print("Landscape") } else { print("Portrait") } }
Swift 3
override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver(self, selector: #selector(ViewController.rotated), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil) } deinit { NotificationCenter.default.removeObserver(self) } func rotated() { if UIDevice.current.orientation.isLandscape { print("Landscape") } else { print("Portrait") } }
источник
viewWillTransition:
ожидает, что изменение произойдет при использовании,UIDeviceOrientationDidChange
вызывается после завершения изменения.shouldAutorotate
представления установлено значениеfalse
. Это удобно для таких экранов, как главный экран приложения «Камера» - ориентация заблокирована, но кнопки могут вращаться.Swift 3 Код выше обновлен:
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) if UIDevice.current.orientation.isLandscape { print("Landscape") } else { print("Portrait") } }
источник
⚠️Device Orientation! = Ориентация интерфейса⚠️
Swift 5. * iOS14 и ниже
Вам действительно стоит различать:
Существует множество сценариев, в которых эти 2 значения не совпадают, например:
В большинстве случаев вы захотите использовать ориентацию интерфейса, и вы можете получить ее через окно:
private var windowInterfaceOrientation: UIInterfaceOrientation? { return UIApplication.shared.windows.first?.windowScene?.interfaceOrientation }
Если вы также хотите поддерживать <iOS 13 (например, iOS 12), вы должны сделать следующее:
private var windowInterfaceOrientation: UIInterfaceOrientation? { if #available(iOS 13.0, *) { return UIApplication.shared.windows.first?.windowScene?.interfaceOrientation } else { return UIApplication.shared.statusBarOrientation } }
Теперь нужно определить, где реагировать на изменение ориентации интерфейса окна. Есть несколько способов сделать это, но оптимальное решение - сделать это внутри
willTransition(to newCollection: UITraitCollection
.Этот унаследованный метод UIViewController, который можно переопределить, будет срабатывать каждый раз при изменении ориентации интерфейса. Следовательно, вы можете делать все свои модификации в последнем.
Вот пример решения :
class ViewController: UIViewController { override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) { super.willTransition(to: newCollection, with: coordinator) coordinator.animate(alongsideTransition: { (context) in guard let windowInterfaceOrientation = self.windowInterfaceOrientation else { return } if windowInterfaceOrientation.isLandscape { // activate landscape changes } else { // activate portrait changes } }) } private var windowInterfaceOrientation: UIInterfaceOrientation? { return UIApplication.shared.windows.first?.windowScene?.interfaceOrientation } }
Реализовав этот метод, вы сможете реагировать на любое изменение ориентации вашего интерфейса. Но имейте в виду, что он не будет запускаться при открытии приложения, поэтому вам также придется вручную обновить свой интерфейс в
viewWillAppear()
.Я создал образец проекта, который подчеркивает разницу между ориентацией устройства и ориентацией интерфейса. Кроме того, это поможет вам понять различное поведение в зависимости от того, на каком этапе жизненного цикла вы решили обновить свой пользовательский интерфейс.
Не стесняйтесь клонировать и запускать следующий репозиторий: https://github.com/wjosset/ReactToOrientation
источник
func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator)
не помогло . Я заставил это работать, используяfunc viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator)
.Swift 4+: я использовал это для дизайна мягкой клавиатуры, и по какой-то причине
UIDevice.current.orientation.isLandscape
метод продолжал говорить мне, что этоPortrait
так, поэтому вот что я использовал вместо этого:override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) if(size.width > self.view.frame.size.width){ //Landscape } else{ //Portrait } }
источник
size
Параметр , который вводится в viewWillTransitionToSize: withCoordinator: метод , который вы написали выше. Это будет отражать точный размер вашего представления после перехода.Swift 4.2, RxSwift
Если нам нужно перезагрузить collectionView.
NotificationCenter.default.rx.notification(UIDevice.orientationDidChangeNotification) .observeOn(MainScheduler.instance) .map { _ in } .bind(to: collectionView.rx.reloadData) .disposed(by: bag)
Swift 4, RxSwift
Если нам нужно перезагрузить collectionView.
NotificationCenter.default.rx.notification(NSNotification.Name.UIDeviceOrientationDidChange) .observeOn(MainScheduler.instance) .map { _ in } .bind(to: collectionView.rx.reloadData) .disposed(by: bag)
источник
Я считаю , что правильный ответ на самом деле является сочетание обоих подходов:
viewWIllTransition(toSize:)
иNotificationCenter
«sUIDeviceOrientationDidChange
.viewWillTransition(toSize:)
уведомляет вас перед переходом.NotificationCenter
UIDeviceOrientationDidChange
уведомит вас после .Вы должны быть очень осторожны. Например, в
UISplitViewController
при вращении устройства в определенные ориентации, тоDetailViewController
получает выталкивается изUISplitViewController
S»viewcontrollers
массив, и надевается на магистрUINavigationController
. Если вы попытаетесь найти контроллер подробного представления до завершения вращения, он может не существовать и выйдет из строя.источник
Если вы используете Swift версии> = 3.0, вы должны применить некоторые обновления кода, как уже говорили другие. Только не забудьте позвонить super:
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) // YOUR CODE OR FUNCTIONS CALL HERE }
Если вы думаете использовать StackView для своих изображений, имейте в виду, что вы можете сделать что-то вроде следующего:
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) if UIDevice.current.orientation.isLandscape { stackView.axis = .horizontal } else { stackView.axis = .vertical } // else }
Если вы используете Interface Builder, не забудьте выбрать пользовательский класс для этого объекта UIStackView в разделе Identity Inspector на правой панели. Затем просто создайте (также через Interface Builder) ссылку IBOutlet на пользовательский экземпляр UIStackView:
@IBOutlet weak var stackView: MyStackView!
Возьмите идею и адаптируйте ее под свои нужды. Надеюсь, это поможет вам!
источник
Swift 4
У меня возникли незначительные проблемы при обновлении представления ViewControllers
UIDevice.current.orientation
, например, при обновлении ограничений ячеек табличного представления во время вращения или анимации подпредставлений.Вместо вышеперечисленных методов я сейчас сравниваю размер перехода с размером представления контроллеров представления. Это кажется правильным путем, поскольку на этом этапе кода у вас есть доступ к обоим:
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) print("Will Transition to size \(size) from super view size \(self.view.frame.size)") if (size.width > self.view.frame.size.width) { print("Landscape") } else { print("Portrait") } if (size.width != self.view.frame.size.width) { // Reload TableView to update cell's constraints. // Ensuring no dequeued cells have old constraints. DispatchQueue.main.async { self.tableView.reloadData() } } }
Вывод на iPhone 6:
Will Transition to size (667.0, 375.0) from super view size (375.0, 667.0) Will Transition to size (375.0, 667.0) from super view size (667.0, 375.0)
источник
Все предыдущие предложения хороши, но небольшое примечание:
а) если ориентация установлена в PLIST, только портрет или , например, Вы будете не уведомлены через viewWillTransition
б) если нам все равно нужно знать, повернул ли пользователь устройство (например, игра или подобное ..), мы можем использовать только:
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.rotated), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
протестировано на Xcode8, iOS11
источник
Вы можете использовать
viewWillTransition(to:with:)
и нажать,animate(alongsideTransition:completion:)
чтобы получить ориентацию интерфейса ПОСЛЕ завершения перехода. Вам просто нужно определить и реализовать протокол, подобный этому, чтобы подключиться к событию. Обратите внимание, что этот код использовался для игры SpriteKit, и ваша конкретная реализация может отличаться.protocol CanReceiveTransitionEvents { func viewWillTransition(to size: CGSize) func interfaceOrientationChanged(to orientation: UIInterfaceOrientation) }
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) guard let skView = self.view as? SKView, let canReceiveRotationEvents = skView.scene as? CanReceiveTransitionEvents else { return } coordinator.animate(alongsideTransition: nil) { _ in if let interfaceOrientation = UIApplication.shared.windows.first?.windowScene?.interfaceOrientation { canReceiveRotationEvents.interfaceOrientationChanged(to: interfaceOrientation) } } canReceiveRotationEvents.viewWillTransition(to: size) }
Вы можете установить точки останова в этих функциях и наблюдать, что они
interfaceOrientationChanged(to orientation: UIInterfaceOrientation)
всегда вызываются послеviewWillTransition(to size: CGSize)
с обновленной ориентацией.источник
Чтобы получить правильную ориентацию при запуске приложения, вы должны его проверить
viewDidLayoutSubviews()
. Другие описанные здесь методы не работают.Вот пример того, как это сделать:
var mFirstStart = true override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() if (mFirstStart) { mFirstStart = false detectOrientation() } } func detectOrientation() { if UIDevice.current.orientation.isLandscape { print("Landscape") // do your stuff here for landscape } else { print("Portrait") // do your stuff here for portrait } } override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { detectOrientation() }
Это будет работать всегда, при первом запуске приложения и при вращении во время работы приложения .
источник
Другой способ определить ориентацию устройства - использовать функцию traitCollectionDidChange (_ :). Система вызывает этот метод при изменении среды интерфейса iOS.
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) //... }
Кроме того, вы можете использовать функцию willTransition (to: with :) (которая вызывается перед traitCollectionDidChange (_ :)), чтобы получить информацию непосредственно перед применением ориентации.
override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) { super.willTransition(to: newCollection, with: coordinator) //... }
источник