[英]How to detect orientation change?
我正在使用 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")
}
}
希望這對其他人有幫助!
謝謝!
根據蘋果文檔:
當視圖控制器的視圖大小被其父級更改時調用此方法(即當其窗口旋轉或調整大小時,根視圖控制器)。
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
if UIDevice.current.orientation.isLandscape {
print("Landscape")
}
if UIDevice.current.orientation.isFlat {
print("Flat")
} else {
print("Portrait")
}
}
我需要在使用帶有AVFoundation
的相機時檢測旋轉,發現didRotate
(現已棄用)和willTransition
方法對我的需求不可靠。 使用 David 發布的通知確實有效,但不適用於 Swift 3.x 及更高版本。
下面使用了一個閉包,這似乎是 Apple 未來的偏好。
var didRotate: (Notification) -> Void = { notification in
switch UIDevice.current.orientation {
case .landscapeLeft, .landscapeRight:
print("landscape")
case .portrait, .portraitUpsideDown:
print("Portrait")
default:
print("other (such as face up & down)")
}
}
設置通知:
NotificationCenter.default.addObserver(forName: UIDevice.orientationDidChangeNotification,
object: nil,
queue: .main,
using: didRotate)
拆除通知:
NotificationCenter.default.removeObserver(self,
name: UIDevice.orientationDidChangeNotification,
object: nil)
關於棄用聲明,我最初的評論具有誤導性,所以我想更新一下。 如前所述, @objc
推理的用法已被棄用,而這又需要使用#selector
。 通過改用閉包,可以避免這種情況,並且您現在有了一個解決方案,可以避免由於調用無效選擇器而導致崩潰。
使用UIDevice
-orientation
屬性是不正確的(即使它在大多數情況下可以工作)並且可能導致一些錯誤,例如UIDeviceOrientation
還考慮設備的方向,如果它是面朝上或朝下,沒有直接配對在這些值的UIInterfaceOrientation
枚舉中。
此外,如果您將應用鎖定在某個特定方向,UIDevice 將在不考慮設備方向的情況下為您提供設備方向。
另一方面,iOS8 已棄用UIViewController
類上的interfaceOrientation
屬性。
有 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)
}
我喜歡檢查方向通知,因為您可以在任何類中添加此功能,無需是視圖或視圖控制器。 即使在您的應用程序委托中。
快速 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
}
從 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`
})
}
在目標 C
-(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
在迅速
func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)
覆蓋此方法以檢測方向變化。
斯威夫特 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")
}
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)")
}
如何在 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
方向。希望有人覺得這有幫助。
斯威夫特 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
}
}
當需要跨各種視圖控制器進行檢測時,很多答案都無濟於事。 這個可以解決問題。
如果你想在旋轉完成后做一些事情,你可以像這樣使用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()
}
}
檢查旋轉是否已更改: 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
}
}
我的方法類似於上面顯示的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
}
}
斯威夫特 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
}
}
}
我使用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
}
}
在 iOS 13.1.2 中,方向始終返回 0,直到設備旋轉。 我需要在發生任何旋轉事件之前調用 UIDevice.current.beginGeneratingDeviceOrientationNotifications() 以獲得實際旋轉。
- (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...
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.