我正在使用Swift,我希望能够在旋转到横向时加载UIViewController,任何人都可以指向正确的方向吗?
我在网上找不到任何东西,文档也有点混淆。
答案 0 :(得分:178)
以下是我的工作原理:
在我AppDelegate.swift
函数内的didFinishLaunchingWithOptions
中:
NotificationCenter.default.addObserver(self, selector: #selector(AppDelegate.rotated), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
然后在AppDelegate类中我放了以下函数:
func rotated() {
if UIDeviceOrientationIsLandscape(UIDevice.current.orientation) {
print("Landscape")
}
if UIDeviceOrientationIsPortrait(UIDevice.current.orientation) {
print("Portrait")
}
}
希望这有助于其他任何人!
谢谢!
答案 1 :(得分:166)
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")
}
}
答案 2 :(得分:53)
使用AVFoundation
相机时需要检测旋转,并发现didRotate
(现已弃用)& willTransition
方法对我的需求不可靠。使用David发布的通知确实有效,但对于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&将是推荐的方法。
如果由于#selector
推断的弃用而使用@objc
函数,这是您将在Swift 4.x项目中收到的编译器警告:
Entry in swift-evolution on this change
设置回调:
// 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)
答案 3 :(得分:17)
使用-orientation
的{{1}}属性不正确(即使它可以在大多数情况下都有效)并且可能会导致一些错误,例如UIDevice
也要考虑如果设备面朝上或朝下,则UIDeviceOrientation
枚举中没有这些值的直接对
此外,如果您将应用程序锁定在某个特定方向,UIDevice将为您提供设备方向,而不考虑这一点
另一方面,iOS8已弃用UIInterfaceOrientation
类的interfaceOrientation
属性。
有两个选项可用于检测界面方向:
仍然缺少一种理解界面方向变化方向的方法,这在动画制作过程中非常重要。
在WWDC 2014的会议中"查看iOS8中的控制器进展"说话者也使用替换UIViewController
的方法提供了解决该问题的方法。
此处提出的解决方案部分实施,更多信息here:
-will/DidRotateToInterfaceOrientation
答案 4 :(得分:11)
很简单,这适用于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)
}
答案 5 :(得分:10)
我知道此问题适用于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
}
答案 6 :(得分:9)
答案 7 :(得分:8)
斯威夫特3 |经常观察到UIDeviceOrientationDidChange通知
每次设备在3D空间中更改方向时,以下代码都会打印“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")
}
答案 8 :(得分:7)
目标C
-(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
在swift中
func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)
重写此方法以检测方向更改。
答案 9 :(得分:5)
如何在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
方向。希望有人觉得这很有帮助。
答案 10 :(得分:5)
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)")
}
答案 11 :(得分:4)
检查轮换是否已更改为: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")
}
}
答案 12 :(得分:4)
以下是检测设备方向的简便方法:( 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
}
}
答案 13 :(得分:4)
如果您想在轮换完成后执行某些操作,可以像这样使用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()
}
}
答案 14 :(得分:3)
我喜欢检查方向通知,因为您可以在任何类中添加此功能,不需要是视图或视图控制器。即使在你的app delegate。
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
}
答案 15 :(得分:2)
我使用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...
}
}
答案 16 :(得分:2)
我的方法类似于上面显示的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
}
}
答案 17 :(得分:2)
从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`
})
}
答案 18 :(得分:2)
快捷键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
}
}
当需要跨各种视图控制器进行检测时,很多答案都无济于事。这是窍门。
答案 19 :(得分:1)
适用于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
}
}
答案 20 :(得分:1)
快速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
}
}
}
答案 21 :(得分:0)
- (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的方向
答案 22 :(得分:0)
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...
}
答案 23 :(得分:0)
在iOS 13.1.2中,方向始终返回0,直到旋转设备为止。我需要在发生任何旋转事件之前调用UIDevice.current.beginGeneratingDeviceOrientationNotifications()以获得实际旋转。