Я использую Swift и хочу иметь возможность загружать UIViewController при повороте на альбомную ориентацию. Может ли кто-нибудь указать мне правильное направление?
Я ничего не могу найти в Интернете и немного смущен документацией.
Я использую Swift и хочу иметь возможность загружать UIViewController при повороте на альбомную ориентацию. Может ли кто-нибудь указать мне правильное направление?
Я ничего не могу найти в Интернете и немного смущен документацией.
Ответы:
Вот как я получил это работает:
В AppDelegate.swiftвнутри didFinishLaunchingWithOptions функции я ставлю:
NotificationCenter.default.addObserver(self, selector: #selector(AppDelegate.rotated), name: UIDevice.orientationDidChangeNotification, object: nil)
а затем внутри класса AppDelegate я поместил следующую функцию:
func rotated() {
if UIDeviceOrientationIsLandscape(UIDevice.current.orientation) {
print("Landscape")
}
if UIDeviceOrientationIsPortrait(UIDevice.current.orientation) {
print("Portrait")
}
}
Надеюсь, это поможет кому-нибудь еще!
Спасибо!
selectorиметь формат строки "rotated:"??
rotated()это не так)
UIDeviceOrientationэто что-то отличное от UIInterfaceOrientation... Это потому, что UIDeviceOrientationтакже обнаруживает ориентацию лицевой стороной вниз и лицевой стороной вверх, что означает, что ваш код может случайным образом перемещаться между книжной и альбомной ориентацией, если ваше устройство лежит на почти плоской, но слегка неровной поверхности (т.е. покачивание на выступающей поверхности). камера
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
if UIDevice.current.orientation.isLandscape {
print("Landscape")
}
if UIDevice.current.orientation.isFlat {
print("Flat")
} else {
print("Portrait")
}
}
Необходимо обнаружить вращение при использовании камеры с AVFoundation, и обнаружил, что didRotate(в настоящее время не рекомендуется ) &willTransition методы были ненадежными для моих нужд. Использование уведомления, опубликованного Дэвидом, сработало, но не актуально для Swift 3.x / 4.x.
Swift 4.2 Имя уведомления было изменено.
Значение закрытия остается таким же, как Swift 4.0:
var didRotate: (Notification) -> Void = { notification in
switch UIDevice.current.orientation {
case .landscapeLeft, .landscapeRight:
print("landscape")
case .portrait, .portraitUpsideDown:
print("Portrait")
default:
print("other")
}
}
Чтобы настроить уведомление для Swift 4.2 :
NotificationCenter.default.addObserver(forName: UIDevice.orientationDidChangeNotification,
object: nil,
queue: .main,
using: didRotate)
Чтобы снять уведомление для Swift 4.2 :
NotificationCenter.default.removeObserver(self,
name: UIDevice.orientationDidChangeNotification,
object: nil)
Что касается заявления об устаревании , мой первоначальный комментарий вводил в заблуждение, поэтому я хотел обновить его. Как уже отмечалось, использование @objcвывода не рекомендуется, что, в свою очередь, было необходимо для использования#selector . Вместо этого можно избежать замыкания, и теперь у вас есть решение, позволяющее избежать сбоя из-за вызова неверного селектора.
Swift 4.0
В Swift 4.0 Apple рекомендовала нам избегать использования #selector, поэтому в этом подходе теперь используется блок завершения. Этот подход также обратно совместим со Swift 3.x и будет рекомендованным подходом в будущем.
Это предупреждение компилятора, которое вы получите в проекте Swift 4.x, если вы используете #selectorфункцию из-за устаревания @objcвывода:
Вступление в стремительную эволюцию по этому изменению .
Настройте обратный вызов:
// If you do not use the notification var in your callback,
// you can safely replace it with _
var didRotate: (Notification) -> Void = { notification in
switch UIDevice.current.orientation {
case .landscapeLeft, .landscapeRight:
print("landscape")
case .portrait, .portraitUpsideDown:
print("Portrait")
default:
print("other")
}
}
Настройте уведомление:
NotificationCenter.default.addObserver(forName: .UIDeviceOrientationDidChange,
object: nil,
queue: .main,
using: didRotate)
Снеси его:
NotificationCenter.default.removeObserver(self, name: .UIDeviceOrientationDidChange, object: nil)
Использование -orientationсвойства of UIDeviceявляется неправильным (даже если оно может работать в большинстве случаев) и может привести к некоторым ошибкам, например, UIDeviceOrientationучитывайте также ориентацию устройства, если оно направлено вверх или вниз, UIInterfaceOrientationдля перечисления нет прямой пары в перечислении. ценности.
Кроме того, если вы заблокируете свое приложение в какой-то определенной ориентации, UIDevice предоставит вам ориентацию устройства без учета этого.
С другой стороны iOS8 устарела interfaceOrientationсобственность на UIViewControllerкласс.
Для определения ориентации интерфейса доступно 2 варианта:
Чего еще не хватает, так это способа понять направление изменения ориентации интерфейса, что очень важно во время анимации.
На сессии WWDC 2014 «Просмотр продвижения контроллера в iOS8» докладчик также предлагает решение этой проблемы, используя заменяющий метод -will/DidRotateToInterfaceOrientation.
Здесь предлагаемое решение частично реализовано, подробнее здесь :
func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
let orientation = orientationFromTransform(coordinator.targetTransform())
let oldOrientation = UIApplication.sharedApplication().statusBarOrientation
myWillRotateToInterfaceOrientation(orientation,duration: duration)
coordinator.animateAlongsideTransition({ (ctx) in
self.myWillAnimateRotationToInterfaceOrientation(orientation,
duration:duration)
}) { (ctx) in
self.myDidAnimateFromInterfaceOrientation(oldOrientation)
}
}
Я знаю, что этот вопрос для Swift, но так как это одна из главных ссылок для поиска Google, и если вы ищете тот же код в Objective-C:
// add the observer
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(rotated:) name:UIDeviceOrientationDidChangeNotification object:nil];
// remove the observer
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];
// method signature
- (void)rotated:(NSNotification *)notification {
// do stuff here
}
Просто, это работает в iOS8 и 9 / Swift 2 / Xcode7, просто поместите этот код в ваш viewcontroller.swift. Он будет печатать размеры экрана при каждом изменении ориентации, вместо этого вы можете указать свой собственный код:
override func didRotateFromInterfaceOrientation(fromInterfaceOrientation: UIInterfaceOrientation) {
getScreenSize()
}
var screenWidth:CGFloat=0
var screenHeight:CGFloat=0
func getScreenSize(){
screenWidth=UIScreen.mainScreen().bounds.width
screenHeight=UIScreen.mainScreen().bounds.height
print("SCREEN RESOLUTION: "+screenWidth.description+" x "+screenHeight.description)
}
didRotateFromInterfaceOrientation()не работает надежно. Он пропускает некоторые повороты. iewWillTransitionToSize:withTransitionCoordinator:работает нормально
Используйте новый viewWillTransitionToSize (_: withTransitionCoordinator :)
Мне нравится проверять уведомление об ориентации, потому что вы можете добавить эту функцию в любой класс, не нужно быть представлением или контроллером представления. Даже в вашем приложении делегат.
SWIFT 5:
//ask the system to start notifying when interface change
UIDevice.current.beginGeneratingDeviceOrientationNotifications()
//add the observer
NotificationCenter.default.addObserver(
self,
selector: #selector(orientationChanged(notification:)),
name: UIDevice.orientationDidChangeNotification,
object: nil)
чем кэширование уведомления
@objc func orientationChanged(notification : NSNotification) {
//your code there
}
В Задаче С
-(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
В быстром
func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)
Переопределите этот метод, чтобы обнаружить изменение ориентации.
Свифт 3 | Уведомление UIDeviceOrientationDidChange наблюдается слишком часто
Следующий код печатает «deviceDidRotate» каждый раз, когда ваше устройство меняет ориентацию в трехмерном пространстве - независимо от перехода из портретной в альбомную ориентацию. Например, если вы держите свой телефон в портретной ориентации и наклоняете его вперед и назад - deviceDidRotate () вызывается повторно.
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(
self,
selector: #selector(deviceDidRotate),
name: .UIDeviceOrientationDidChange,
object: nil
)
}
func deviceDidRotate() {
print("deviceDidRotate")
}
Чтобы обойти это, вы можете сохранить предыдущую ориентацию устройства и проверить наличие изменений в deviceDidRotate ().
var previousDeviceOrientation: UIDeviceOrientation = UIDevice.current.orientation
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(
self,
selector: #selector(deviceDidRotate),
name: .UIDeviceOrientationDidChange,
object: nil
)
}
func deviceDidRotate() {
if UIDevice.current.orientation == previousDeviceOrientation { return }
previousDeviceOrientation = UIDevice.current.orientation
print("deviceDidRotate")
}
Или вы можете использовать другое уведомление, которое вызывается только тогда, когда устройство меняет альбомную ориентацию на книжную. В этом случае вы хотите использовать UIApplicationDidChangeStatusBarOrientationуведомление.
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(
self,
selector: #selector(deviceDidRotate),
name: .UIApplicationDidChangeStatusBarOrientation,
object: nil
)
}
func deviceDidRotate() {
print("deviceDidRotate")
}
Полная рабочая реализация того, как обнаружить изменение ориентации в Swift 3.0.
Я решил использовать эту реализацию, потому что телефонные ориентации face upи face downбыли важны для меня, и я хотел, чтобы представление изменилось, только когда я знал, что ориентация была в указанной позиции.
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//1
NotificationCenter.default.addObserver(self, selector: #selector(deviceOrientationDidChange), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
}
deinit {
//3
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
}
func deviceOrientationDidChange() {
//2
switch UIDevice.current.orientation {
case .faceDown:
print("Face down")
case .faceUp:
print("Face up")
case .unknown:
print("Unknown")
case .landscapeLeft:
print("Landscape left")
case .landscapeRight:
print("Landscape right")
case .portrait:
print("Portrait")
case .portraitUpsideDown:
print("Portrait upside down")
}
}
}
Важные моменты, на которые следует обратить внимание:
unknownориентация есть.Надеюсь, кто-то найдет это полезным.
override func didRotate(from fromInterfaceOrientation: UIInterfaceOrientation) {
//swift 3
getScreenSize()
}
func getScreenSize(){
let screenWidth = UIScreen.main.bounds.width
let screenHeight = UIScreen.main.bounds.height
print("SCREEN RESOLUTION: \(screenWidth.description) x \(screenHeight.description)")
}
Если вы хотите сделать что-то ПОСЛЕ того, как вращение завершено, вы можете использовать UIViewControllerTransitionCoordinatorобработчик завершения следующим образом
public override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
// Hook in to the rotation animation completion handler
coordinator.animate(alongsideTransition: nil) { (_) in
// Updates to your UI...
self.tableView.reloadData()
}
}
Начиная с iOS 8 это правильный способ сделать это.
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
coordinator.animate(alongsideTransition: { context in
// This is called during the animation
}, completion: { context in
// This is called after the rotation is finished. Equal to deprecated `didRotate`
})
}
Проверьте, изменилось ли вращение с: viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)
С coordinator.animateAlongsideTransition(nil) { (UIViewControllerTransitionCoordinatorContext) вы можете проверить, завершен ли переход.
Смотрите код ниже:
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
coordinator.animateAlongsideTransition(nil) { (UIViewControllerTransitionCoordinatorContext) in
// if you want to execute code after transition finished
print("Transition finished")
}
if size.height < size.width {
// Landscape
print("Landscape")
} else {
// Portrait
print("Portrait")
}
}
Вот простой способ определить ориентацию устройства: ( Swift 3 )
override func willRotate(to toInterfaceOrientation: UIInterfaceOrientation, duration: TimeInterval) {
handleViewRotaion(orientation: toInterfaceOrientation)
}
//MARK: - Rotation controls
func handleViewRotaion(orientation:UIInterfaceOrientation) -> Void {
switch orientation {
case .portrait :
print("portrait view")
break
case .portraitUpsideDown :
print("portraitUpsideDown view")
break
case .landscapeLeft :
print("landscapeLeft view")
break
case .landscapeRight :
print("landscapeRight view")
break
case .unknown :
break
}
}
willRotateустарела, лучше использовать viewWillTransition.
Свифт 4:
override func viewWillAppear(_ animated: Bool) {
NotificationCenter.default.addObserver(self, selector: #selector(deviceRotated), name: UIDevice.orientationDidChangeNotification, object: nil)
}
override func viewWillDisappear(_ animated: Bool) {
NotificationCenter.default.removeObserver(self, name: UIDevice.orientationDidChangeNotification, object: nil)
}
@objc func deviceRotated(){
if UIDevice.current.orientation.isLandscape {
//Code here
} else {
//Code here
}
}
Многие ответы не помогают, когда нужно обнаруживать различные контроллеры представления. Этот делает свое дело.
viewWillDisappearи добавить addObserverв viewDidLoad. iOS отписывается от просмотра контроллера автоматически.
UIDevice.current.orientation.isFlat
Мой подход подобен тому, что показывает bpedit выше, но с фокусом на iOS 9+. Я хотел изменить область FSCalendar, когда представление вращается.
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
coordinator.animateAlongsideTransition({ (context) in
if size.height < size.width {
self.calendar.setScope(.Week, animated: true)
self.calendar.appearance.cellShape = .Rectangle
}
else {
self.calendar.appearance.cellShape = .Circle
self.calendar.setScope(.Month, animated: true)
}
}, completion: nil)
}
Это ниже работало, но я чувствовал себя застенчиво об этом :)
coordinator.animateAlongsideTransition({ (context) in
if size.height < size.width {
self.calendar.scope = .Week
self.calendar.appearance.cellShape = .Rectangle
}
}) { (context) in
if size.height > size.width {
self.calendar.scope = .Month
self.calendar.appearance.cellShape = .Circle
}
}
Я использую, UIUserInterfaceSizeClassчтобы определить ориентацию, измененную в UIViewControllerклассе, вот так:
override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) {
let isiPadLandscapePortrait = newCollection.horizontalSizeClass == .regular && newCollection.verticalSizeClass == .regular
let isiPhonePlustLandscape = newCollection.horizontalSizeClass == .regular && newCollection.verticalSizeClass == .compact
let isiPhonePortrait = newCollection.horizontalSizeClass == .compact && newCollection.verticalSizeClass == .regular
let isiPhoneLandscape = newCollection.horizontalSizeClass == .compact && newCollection.verticalSizeClass == .compact
if isiPhonePortrait {
// do something...
}
}
Для Swift 3
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
if UIDevice.current.orientation.isLandscape {
//Landscape
}
else if UIDevice.current.orientation.isFlat {
//isFlat
}
else {
//Portrait
}
}
UIDevice.current.orientation.isFlat
Swift 5
Настройка класса для получения уведомлений об изменении ориентации устройства:
class MyClass {
...
init (...) {
...
super.init(...)
// subscribe to device orientation change notifications
UIDevice.current.beginGeneratingDeviceOrientationNotifications()
NotificationCenter.default.addObserver(self, selector: #selector(orientationChanged), name: UIDevice.orientationDidChangeNotification, object: nil)
...
}
...
}
Код обработчика установки:
@objc extension MyClass {
func orientationChanged(_ notification: NSNotification) {
let device = notification.object as! UIDevice
let deviceOrientation = device.orientation
switch deviceOrientation {
case .landscapeLeft: //do something for landscape left
case .landscapeRight: //do something for landscape right
case .portrait: //do something for portrait
case .portraitUpsideDown: //do something for portrait upside-down
case .faceDown: //do something for face down
case .faceUp: //do something for face up
case .unknown: //handle unknown
@unknown default: //handle unknown default
}
}
}
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(OrientationDidChange:) name:UIDeviceOrientationDidChangeNotification object:nil];
}
-(void)OrientationDidChange:(NSNotification*)notification {
UIDeviceOrientation Orientation=[[UIDevice currentDevice]orientation];
if(Orientation==UIDeviceOrientationLandscapeLeft || Orientation==UIDeviceOrientationLandscapeRight) {
NSLog(@"Landscape");
} else if(Orientation==UIDeviceOrientationPortrait) {
NSLog(@"Potrait Mode");
}
}
ПРИМЕЧАНИЕ. Просто используйте этот код, чтобы определить, в каком направлении находится UIViewController.
override func viewDidLoad() {
NotificationCenter.default.addObserver(self, selector: #selector(MyController.rotated), name: UIDevice.orientationDidChangeNotification, object: nil)
//...
}
@objc
private func rotated() {
if UIDevice.current.orientation.isLandscape {
} else if UIDevice.current.orientation.isPortrait {
}
//or you can check orientation separately UIDevice.current.orientation
//portrait, portraitUpsideDown, landscapeLeft, landscapeRight...
}
В iOS 13.1.2 ориентация всегда возвращает 0, пока устройство не будет повернуто. Мне нужно вызвать UIDevice.current.beginGeneratingDeviceOrientationNotifications (), чтобы получить фактическое вращение до того, как произойдет любое событие поворота.