我使用的是Swift,我希望能够在旋转到横向时加载UIViewController,有人可以指出正确的方向吗?
我在网上找不到任何东西,并且对文档有些困惑。
我使用的是Swift,我希望能够在旋转到横向时加载UIViewController,有人可以指出正确的方向吗?
我在网上找不到任何东西,并且对文档有些困惑。
Answers:
这是我的工作方式:
在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
还可以检测面朝下和面朝上的方向,这意味着如果您的设备位于几乎平坦但略微不平坦的表面上(例如,在突出部分上摇摆),则代码可以在纵向和横向之间随机跳转。 6 / 6s的摄影机)
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
方法不符合我的需求。使用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项目中收到该警告:
设置回调:
// 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:
可以。
我喜欢检查方向通知,因为您可以在任何类中添加此功能,而无需成为视图或视图控制器。即使在您的应用程序委托中。
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
}
雨燕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")
}
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
斯威夫特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()以获得实际旋转。