Karena aplikasi saya mendapat dukungan untuk semua orientasi. Saya hanya ingin mengunci mode potret ke UIViewController tertentu.
misalnya menganggap itu Aplikasi Tab dan ketika Tampilan Masuk muncul secara sederhana, saya hanya ingin Tampilan Masuk itu ke mode potret saja tidak peduli bagaimana pengguna memutar perangkat atau bagaimana orientasi perangkat saat ini.
swift
uiviewcontroller
portrait
device-orientation
Thiha Aung
sumber
sumber
Jawaban:
Hal-hal bisa menjadi sangat berantakan ketika Anda memiliki hierarki tampilan yang rumit, seperti memiliki beberapa pengontrol navigasi dan / atau pengontrol tampilan tab.
Implementasi ini menempatkannya pada pengontrol tampilan individu untuk disetel kapan mereka ingin mengunci orientasi, alih-alih mengandalkan Delegasi Aplikasi untuk menemukannya dengan mengulang melalui subview.
Cepat 3, 4, 5
Di AppDelegate:
/// set orientations you want to be allowed in this property by default var orientationLock = UIInterfaceOrientationMask.all func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask { return self.orientationLock }
Di beberapa kelas struct atau helper global lainnya, di sini saya membuat AppUtility:
struct AppUtility { static func lockOrientation(_ orientation: UIInterfaceOrientationMask) { if let delegate = UIApplication.shared.delegate as? AppDelegate { delegate.orientationLock = orientation } } /// OPTIONAL Added method to adjust lock and rotate to the desired orientation static func lockOrientation(_ orientation: UIInterfaceOrientationMask, andRotateTo rotateOrientation:UIInterfaceOrientation) { self.lockOrientation(orientation) UIDevice.current.setValue(rotateOrientation.rawValue, forKey: "orientation") UINavigationController.attemptRotationToDeviceOrientation() } }
Kemudian di ViewController yang diinginkan, Anda ingin mengunci orientasi:
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) AppUtility.lockOrientation(.portrait) // Or to rotate and lock // AppUtility.lockOrientation(.portrait, andRotateTo: .portrait) } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) // Don't forget to reset when view is being removed AppUtility.lockOrientation(.all) }
Jika iPad atau Aplikasi Universal
Pastikan bahwa "Membutuhkan layar penuh" dicentang di Pengaturan Target -> Umum -> Info Penerapan.
supportedInterfaceOrientationsFor
delegasi tidak akan dipanggil jika tidak dicentang.sumber
Requires full screen
, itu akan mencegah aplikasi tersedia untuk Slide Over dan Split View. Lihat Mengadopsi Peningkatan Multitasking di iPad oleh Apple. Saya punya jawaban tidak perlu mengaktifkanRequires full screen
Cepat 4
AppDelegate
var orientationLock = UIInterfaceOrientationMask.all func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask { return self.orientationLock } struct AppUtility { static func lockOrientation(_ orientation: UIInterfaceOrientationMask) { if let delegate = UIApplication.shared.delegate as? AppDelegate { delegate.orientationLock = orientation } } static func lockOrientation(_ orientation: UIInterfaceOrientationMask, andRotateTo rotateOrientation:UIInterfaceOrientation) { self.lockOrientation(orientation) UIDevice.current.setValue(rotateOrientation.rawValue, forKey: "orientation") } }
Baris ViewController Tambahkan Mengikuti jika Anda hanya memerlukan orientasi potret. Anda harus menerapkan ini ke semua kebutuhan ViewController untuk menampilkan mode potret.
override func viewWillAppear(_ animated: Bool) { AppDelegate.AppUtility.lockOrientation(UIInterfaceOrientationMask.portrait, andRotateTo: UIInterfaceOrientation.portrait) }
dan itu akan membuat orientasi layar untuk Viewcontroller lain sesuai dengan orientasi fisik perangkat.
override func viewWillDisappear(_ animated: Bool) { AppDelegate.AppUtility.lockOrientation(UIInterfaceOrientationMask.all) }
sumber
func application
dalam delegasi aplikasi dengan fungsi inifunc application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask { return self.orientationLock ?
Cepat 3 & 4
Setel
supportedInterfaceOrientations
properti UIViewControllers tertentu seperti ini:class MyViewController: UIViewController { var orientations = UIInterfaceOrientationMask.portrait //or what orientation you want override var supportedInterfaceOrientations : UIInterfaceOrientationMask { get { return self.orientations } set { self.orientations = newValue } } override func viewDidLoad() { super.viewDidLoad() } //... }
MEMPERBARUI
Solusi ini hanya bekerja ketika Anda
viewController
sedang tidak tertanam dalamUINavigationController
, karena mewarisi orientasi dari orang tua viewController.Untuk kasus ini, Anda dapat membuat subkelas
UINavigationViewController
dan menyetel properti ini di atasnya.sumber
Tambahkan kode ini untuk memaksa potret dan menguncinya:
override func viewDidLoad() { super.viewDidLoad() // Force the device in portrait mode when the view controller gets loaded UIDevice.currentDevice().setValue(UIInterfaceOrientation.Portrait.rawValue, forKey: "orientation") } override func shouldAutorotate() -> Bool { // Lock autorotate return false } override func supportedInterfaceOrientations() -> Int { // Only allow Portrait return Int(UIInterfaceOrientationMask.Portrait.rawValue) } override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation { // Only allow Portrait return UIInterfaceOrientation.Portrait }
Di AppDelegate Anda - setel supportInterfaceOrientationsForWindow ke orientasi apa pun yang Anda inginkan agar didukung oleh seluruh aplikasi:
func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask { return UIInterfaceOrientationMask.All }
sumber
Ini adalah solusi umum untuk masalah Anda dan orang lain yang terkait.
1. Buat kelas bantu UIHelper dan gunakan metode berikut:
/**This method returns top view controller in application */ class func topViewController() -> UIViewController? { let helper = UIHelper() return helper.topViewControllerWithRootViewController(rootViewController: UIApplication.shared.keyWindow?.rootViewController) } /**This is a recursive method to select the top View Controller in a app, either with TabBarController or not */ private func topViewControllerWithRootViewController(rootViewController:UIViewController?) -> UIViewController? { if(rootViewController != nil) { // UITabBarController if let tabBarController = rootViewController as? UITabBarController, let selectedViewController = tabBarController.selectedViewController { return self.topViewControllerWithRootViewController(rootViewController: selectedViewController) } // UINavigationController if let navigationController = rootViewController as? UINavigationController ,let visibleViewController = navigationController.visibleViewController { return self.topViewControllerWithRootViewController(rootViewController: visibleViewController) } if ((rootViewController!.presentedViewController) != nil) { let presentedViewController = rootViewController!.presentedViewController; return self.topViewControllerWithRootViewController(rootViewController: presentedViewController!); }else { return rootViewController } } return nil }
2. Buat Protokol dengan perilaku keinginan Anda, untuk kasus khusus Anda akan menjadi potret.
orientasi protokolIsOnlyPortrait {}
Nota: Jika mau, tambahkan di bagian atas UIHelper Class.
3. Perluas Pengontrol Tampilan Anda
Dalam kasus Anda:
class Any_ViewController: UIViewController,orientationIsOnlyPortrait { .... }
4. Dalam kelas delegasi aplikasi tambahkan metode ini:
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask { let presentedViewController = UIHelper.topViewController() if presentedViewController is orientationIsOnlyPortrait { return .portrait } return .all }
Catatan Akhir:
sumber
Untuk versi baru Swift, coba ini
override var shouldAutorotate: Bool { return false } override var supportedInterfaceOrientations: UIInterfaceOrientationMask { return UIInterfaceOrientationMask.portrait } override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation { return UIInterfaceOrientation.portrait }
sumber
Sekumpulan jawaban bagus di utas ini, tetapi tidak ada yang sesuai dengan kebutuhan saya. Saya memiliki aplikasi tab dengan pengontrol navigasi di setiap tab, dan satu tampilan perlu diputar, sementara yang lain perlu dikunci dalam potret. Pengontrol navigasi tidak mengubah ukuran subviewnya dengan benar, untuk beberapa alasan. Menemukan solusi (di Swift 3) dengan menggabungkan jawaban ini , dan masalah tata letak menghilang. Buat struct seperti yang disarankan oleh @bmjohns:
import UIKit struct OrientationLock { static func lock(to orientation: UIInterfaceOrientationMask) { if let delegate = UIApplication.shared.delegate as? AppDelegate { delegate.orientationLock = orientation } } static func lock(to orientation: UIInterfaceOrientationMask, andRotateTo rotateOrientation: UIInterfaceOrientation) { self.lock(to: orientation) UIDevice.current.setValue(rotateOrientation.rawValue, forKey: "orientation") } }
Kemudian subclass UITabBarController:
import UIKit class TabBarController: UITabBarController, UITabBarControllerDelegate { required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) self.delegate = self } func tabBarControllerSupportedInterfaceOrientations(_ tabBarController: UITabBarController) -> UIInterfaceOrientationMask { if tabBarController.selectedViewController is MyViewControllerNotInANavigationControllerThatShouldRotate { return .allButUpsideDown } else if let navController = tabBarController.selectedViewController as? UINavigationController, navController.topViewController is MyViewControllerInANavControllerThatShouldRotate { return .allButUpsideDown } else { //Lock view that should not be able to rotate return .portrait } } func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool { if viewController is MyViewControllerNotInANavigationControllerThatShouldRotate { OrientationLock.lock(to: .allButUpsideDown) } else if let navController = viewController as? UINavigationController, navController.topViewController is MyViewControllerInANavigationControllerThatShouldRotate { OrientationLock.lock(to: .allButUpsideDown) } else { //Lock orientation and rotate to desired orientation OrientationLock.lock(to: .portrait, andRotateTo: .portrait) } return true } }
Jangan lupa untuk mengubah kelas TabBarController di storyboard menjadi subkelas yang baru dibuat.
sumber
Berikut adalah cara sederhana yang berfungsi untuk saya dengan Swift 4.2 (iOS 12.2), letakkan ini di tempat
UIViewController
yang ingin Anda nonaktifkan shouldAutorotate:override var supportedInterfaceOrientations: UIInterfaceOrientationMask { return .portrait }
Bagian tersebut
.portrait
memberi tahu orientasi mana yang akan tetap ada, Anda dapat mengubahnya sesuka Anda. Pilihannya adalah:.portrait
,.all
,.allButUpsideDown
,.landscape
,.landscapeLeft
,.landscapeRight
,.portraitUpsideDown
.sumber
Untuk menyetel orientasi Lanskap ke semua tampilan aplikasi Anda & mengizinkan hanya satu tampilan ke Semua orientasi (untuk dapat menambahkan rol kamera misalnya):
Di AppDelegate.swift:
var adaptOrientation = false
Dalam: didFinishLaunchingWithOptions
NSNotificationCenter.defaultCenter().addObserver(self, selector: "adaptOrientationAction:", name:"adaptOrientationAction", object: nil)
Di tempat lain di AppDelegate.swift:
func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> Int { return checkOrientation(self.window?.rootViewController) } func checkOrientation(viewController:UIViewController?)-> Int{ if (adaptOrientation == false){ return Int(UIInterfaceOrientationMask.Landscape.rawValue) }else { return Int(UIInterfaceOrientationMask.All.rawValue) } } func adaptOrientationAction(notification: NSNotification){ if adaptOrientation == false { adaptOrientation = true }else { adaptOrientation = false } }
Kemudian dalam tampilan yang beralih ke tampilan yang Anda inginkan agar dapat memiliki Semua orientasi:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) { if (segue.identifier == "YOURSEGUE") { NSNotificationCenter.defaultCenter().postNotificationName("adaptOrientationAction", object: nil) } } override func viewWillAppear(animated: Bool) { if adaptOrientation == true { NSNotificationCenter.defaultCenter().postNotificationName("adaptOrientationAction", object: nil) } }
Hal terakhir adalah mencentang Orientasi perangkat: - Portrait - Landscape Left - Landscape Right
sumber
Buat ekstensi baru dengan
import UIKit extension UINavigationController { override open var supportedInterfaceOrientations: UIInterfaceOrientationMask { return .portrait } } extension UITabBarController { override open var supportedInterfaceOrientations: UIInterfaceOrientationMask { return .portrait } }
sumber
bmjohns -> Anda adalah penyelamat hidup saya. Itulah satu-satunya solusi yang berfungsi (Dengan struktur AppUtility)
Saya telah membuat kelas ini:
class Helper{ struct AppUtility { static func lockOrientation(_ orientation: UIInterfaceOrientationMask) { if let delegate = UIApplication.shared.delegate as? AppDelegate { delegate.orientationLock = orientation } } /// OPTIONAL Added method to adjust lock and rotate to the desired orientation static func lockOrientation(_ orientation: UIInterfaceOrientationMask, andRotateTo rotateOrientation:UIInterfaceOrientation) { self.lockOrientation(orientation) UIDevice.current.setValue(rotateOrientation.rawValue, forKey: "orientation") } } }
dan mengikuti instruksi Anda, dan semuanya bekerja dengan sempurna untuk Swift 3 -> xcode versi 8.2.1
sumber
Mulai iOS 10 dan 11, iPad mendukung Slide Over dan Split View. Untuk mengaktifkan aplikasi di Slide Over dan Split View,
Requires full screen
harus tidak dicentang. Itu berarti jawaban yang diterima tidak dapat digunakan jika aplikasi ingin mendukung Slide Over dan Split View. Lihat selengkapnya dari Apple's Adopting Multitasking Enhancements di iPad di sini .Saya memiliki solusi yang memungkinkan (1) menghapus centang
Requires full screen
, (2) hanya satu fungsi yang akan diterapkanappDelegate
(terutama jika Anda tidak ingin / tidak dapat mengubah pengontrol tampilan target), dan (3) menghindari panggilan rekursif. Tidak perlu class helper atau extension.appDelegate.swift (Swift 4)
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask { // Search for the visible view controller var vc = window?.rootViewController // Dig through tab bar and navigation, regardless their order while (vc is UITabBarController) || (vc is UINavigationController) { if let c = vc as? UINavigationController { vc = c.topViewController } else if let c = vc as? UITabBarController { vc = c.selectedViewController } } // Look for model view controller while (vc?.presentedViewController) != nil { vc = vc!.presentedViewController } print("vc = " + (vc != nil ? String(describing: type(of: vc!)) : "nil")) // Final check if it's our target class. Also make sure it isn't exiting. // Otherwise, system will mistakenly rotate the presentingViewController. if (vc is TargetViewController) && !(vc!.isBeingDismissed) { return [.portrait] } return [.all] }
Edit
@bmjohns menunjukkan bahwa fungsi ini tidak dipanggil di iPad. Saya memverifikasi dan ya itu tidak disebut. Jadi, saya melakukan sedikit pengujian lagi dan menemukan beberapa fakta:
Requires full screen
karena saya ingin mengaktifkan Slide Over dan Slide View di iPad. Untuk itu dibutuhkan aplikasi untuk mendukung semua 4 orientasi untuk iPad, di Info.plist:Supported interface orientations (iPad)
.Aplikasi saya bekerja dengan cara yang sama seperti Facebook: di iPhone, sebagian besar waktu terkunci untuk potret. Saat melihat gambar dalam layar penuh, memungkinkan pengguna untuk memutar lanskap untuk tampilan yang lebih baik. Di iPad, pengguna dapat memutar ke orientasi apa pun di pengontrol tampilan mana pun. Jadi, aplikasi terlihat bagus saat iPad berdiri di atas Smart Cover (lanskap kiri).
Agar iPad dapat menelepon
application(_:supportedInterfaceOrientationsFor)
, di Info.plist, simpan hanya potret untuk iPad. Aplikasi akan kehilangan kemampuan Slide Over + Split View. Tetapi Anda dapat mengunci atau membuka kunci orientasi untuk pengontrol tampilan apa pun, hanya di satu tempat dan tidak perlu mengubah kelas ViewController.Terakhir, fungsi ini dipanggil pada siklus hidup pengontrol tampilan, saat tampilan ditampilkan / dihapus. Jika aplikasi Anda perlu mengunci / membuka / mengubah orientasi di lain waktu, itu mungkin tidak berfungsi
sumber
Solusi teruji yang sebenarnya untuk ini.Dalam contoh saya, saya ingin seluruh aplikasi saya harus dalam mode potret, tetapi hanya satu orientasi layar yang harus dalam mode lanskap.
Kode di AppDelegate seperti jawaban di atas dijelaskan.
var orientationLock = UIInterfaceOrientationMask.all func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask { return self.orientationLock } struct AppUtility { static func lockOrientation(_ orientation: UIInterfaceOrientationMask) { if let delegate = UIApplication.shared.delegate as? AppDelegate { delegate.orientationLock = orientation } } static func lockOrientation(_ orientation: UIInterfaceOrientationMask, andRotateTo rotateOrientation:UIInterfaceOrientation) { self.lockOrientation(orientation) UIDevice.current.setValue(rotateOrientation.rawValue, forKey: "orientation") } }
Kemudian tuliskan kode ini sebelum viewcontroller orientasi lanskap Anda akan disajikan / dorong.
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) AppDelegate.AppUtility.lockOrientation(UIInterfaceOrientationMask.portrait, andRotateTo: UIInterfaceOrientation.portrait) }
Kemudian tulis kode ini di viewcontroller sebenarnya (Untuk tampilan lanskap)
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) AppDelegate.AppUtility.lockOrientation(UIInterfaceOrientationMask.landscape, andRotateTo: UIInterfaceOrientation.landscape) }
sumber
Terima kasih untuk jawaban @ bmjohn di atas. Berikut adalah versi Xamarin / C # yang berfungsi dari kode jawaban itu, untuk menghemat waktu transkripsi:
AppDelegate.cs
public UIInterfaceOrientationMask OrientationLock = UIInterfaceOrientationMask.All; public override UIInterfaceOrientationMask GetSupportedInterfaceOrientations(UIApplication application, UIWindow forWindow) { return this.OrientationLock; }
Kelas Static OrientationUtility.cs:
public static class OrientationUtility { public static void LockOrientation(UIInterfaceOrientationMask orientation) { var appdelegate = (AppDelegate) UIApplication.SharedApplication.Delegate; if(appdelegate != null) { appdelegate.OrientationLock = orientation; } } public static void LockOrientation(UIInterfaceOrientationMask orientation, UIInterfaceOrientation RotateToOrientation) { LockOrientation(orientation); UIDevice.CurrentDevice.SetValueForKey(new NSNumber((int)RotateToOrientation), new NSString("orientation")); } }
Lihat Pengontrol:
public override void ViewDidAppear(bool animated) { base.ViewWillAppear(animated); OrientationUtility.LockOrientation(UIInterfaceOrientationMask.Portrait, UIInterfaceOrientation.Portrait); } public override void ViewWillDisappear(bool animated) { base.ViewWillDisappear(animated); OrientationUtility.LockOrientation(UIInterfaceOrientationMask.All); }
sumber
Saya bereksperimen sedikit dan saya berhasil menemukan solusi bersih untuk masalah ini. Pendekatan tersebut didasarkan pada penandaan tampilan melalui view-> tag
Di target ViewController cukup tetapkan tag ke tampilan root seperti pada contoh kode berikut:
class MyViewController: BaseViewController { // declare unique view tag identifier static let ViewTag = 2105981; override func viewDidLoad() { super.viewDidLoad(); // assign the value to the current root view self.view.tag = MyViewController.ViewTag; }
Dan terakhir di AppDelegate.swift periksa apakah tampilan yang saat ini ditampilkan adalah yang kami beri tag:
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask { if (window?.viewWithTag(DesignerController.ViewTag)) != nil { return .portrait; } return .all; }
Pendekatan ini telah diuji dengan simulator saya dan tampaknya berfungsi dengan baik.
Catatan: tampilan yang ditandai juga akan ditemukan jika MVC saat ini tumpang tindih dengan beberapa ViewController anak dalam tumpukan navigasi.
sumber
Solusi Terbaik untuk mengunci dan mengubah orientasi pada potret dan lanskap:
Tonton video ini di YouTube:
https://m.youtube.com/watch?v=4vRrHdBowyo
Tutorial ini terbaik dan sederhana.
atau gunakan kode di bawah ini:
Lihat gambar ini
// 1- di viewcontroller kedua kami menyetel landscapeleft dan di viewcontroller pertama kami menyetel portrat:
// 2- jika Anda menggunakan NavigationController, Anda harus menambahkan ekstensi
import UIKit class SecondViewController: UIViewController { override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) UIDevice.current.setValue(UIInterfaceOrientation.landscapeLeft.rawValue, forKey: "orientation") } override open var shouldAutorotate: Bool { return false } override open var supportedInterfaceOrientations: UIInterfaceOrientationMask { return .landscapeLeft } override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation { return .landscapeLeft } override func viewDidLoad() { super.viewDidLoad() } //write The rest of your code in here } //if you use NavigationController, you should add this extension extension UINavigationController { override open var supportedInterfaceOrientations: UIInterfaceOrientationMask { return topViewController?.supportedInterfaceOrientations ?? .allButUpsideDown } }
sumber