Saya ingin menambahkan dua gambar ke tampilan gambar tunggal (yaitu untuk gambar lanskap satu dan untuk potret gambar lain) tetapi saya tidak tahu bagaimana mendeteksi perubahan orientasi menggunakan bahasa cepat.
Saya mencoba jawaban ini tetapi hanya membutuhkan satu gambar
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
if UIDevice.currentDevice().orientation.isLandscape.boolValue {
print("Landscape")
} else {
print("Portrait")
}
}
Saya baru dalam pengembangan iOS, saran apa pun akan sangat dihargai!
Jawaban:
let const = "Background" //image name let const2 = "GreyBackground" // image name @IBOutlet weak var imageView: UIImageView! override func viewDidLoad() { super.viewDidLoad() imageView.image = UIImage(named: const) // Do any additional setup after loading the view. } override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) if UIDevice.current.orientation.isLandscape { print("Landscape") imageView.image = UIImage(named: const2) } else { print("Portrait") imageView.image = UIImage(named: const) } }
sumber
viewWillTransition
saat membuat subclassUIView
?.isFlat
. Jika Anda hanya ingin menangkapportrait
saya sarankan Anda mengubah klausa else menjadielse if UIDevice.current.orientation.isPortrait
. Catatan:.isFlat
bisa terjadi baik dalam potret maupun lanskap, dan dengan cara lain {} akan selalu ada default (meskipun lanskap datar).Menggunakan NotificationCenter dan UIDevice 's
beginGeneratingDeviceOrientationNotifications
Swift 4.2+
override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver(self, selector: #selector(ViewController.rotated), name: UIDevice.orientationDidChangeNotification, object: nil) } deinit { NotificationCenter.default.removeObserver(self, name: UIDevice.orientationDidChangeNotification, object: nil) } func rotated() { if UIDevice.current.orientation.isLandscape { print("Landscape") } else { print("Portrait") } }
Cepat 3
override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver(self, selector: #selector(ViewController.rotated), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil) } deinit { NotificationCenter.default.removeObserver(self) } func rotated() { if UIDevice.current.orientation.isLandscape { print("Landscape") } else { print("Portrait") } }
sumber
viewWillTransition:
mengantisipasi perubahan akan terjadi saat menggunakanUIDeviceOrientationDidChange
dipanggil setelah perubahan selesai.shouldAutorotate
disetel kefalse
. Ini berguna untuk layar seperti layar utama aplikasi Kamera - orientasinya terkunci tetapi tombolnya dapat berputar.Kode Swift 3 Di Atas diperbarui:
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) if UIDevice.current.orientation.isLandscape { print("Landscape") } else { print("Portrait") } }
sumber
⚠️ Orientasi Perangkat! = Orientasi Antarmuka⚠️
Swift 5. * iOS14 dan yang lebih lama
Anda harus benar-benar membuat perbedaan antara:
Ada banyak skenario di mana 2 nilai tersebut tidak cocok seperti:
Dalam kebanyakan kasus, Anda ingin menggunakan orientasi antarmuka dan Anda bisa mendapatkannya melalui jendela:
private var windowInterfaceOrientation: UIInterfaceOrientation? { return UIApplication.shared.windows.first?.windowScene?.interfaceOrientation }
Jika Anda juga ingin mendukung <iOS 13 (seperti iOS 12), Anda harus melakukan hal berikut:
private var windowInterfaceOrientation: UIInterfaceOrientation? { if #available(iOS 13.0, *) { return UIApplication.shared.windows.first?.windowScene?.interfaceOrientation } else { return UIApplication.shared.statusBarOrientation } }
Sekarang Anda perlu menentukan di mana harus bereaksi terhadap perubahan orientasi antarmuka jendela. Ada banyak cara untuk melakukan itu tetapi solusi optimal adalah melakukannya di dalam
willTransition(to newCollection: UITraitCollection
.Metode UIViewController yang diwariskan yang dapat diganti ini akan dipicu setiap kali orientasi antarmuka diubah. Akibatnya, Anda dapat melakukan semua modifikasi Anda dengan yang terakhir.
Berikut adalah contoh solusi :
class ViewController: UIViewController { override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) { super.willTransition(to: newCollection, with: coordinator) coordinator.animate(alongsideTransition: { (context) in guard let windowInterfaceOrientation = self.windowInterfaceOrientation else { return } if windowInterfaceOrientation.isLandscape { // activate landscape changes } else { // activate portrait changes } }) } private var windowInterfaceOrientation: UIInterfaceOrientation? { return UIApplication.shared.windows.first?.windowScene?.interfaceOrientation } }
Dengan menerapkan metode ini, Anda akan dapat bereaksi terhadap perubahan orientasi apa pun ke antarmuka Anda. Namun perlu diingat bahwa itu tidak akan dipicu pada pembukaan aplikasi sehingga Anda juga harus memperbarui antarmuka Anda secara manual
viewWillAppear()
.Saya telah membuat proyek contoh yang menggarisbawahi perbedaan antara orientasi perangkat dan orientasi antarmuka. Selain itu, ini akan membantu Anda memahami berbagai perilaku bergantung pada langkah siklus hidup mana yang Anda putuskan untuk memperbarui UI.
Jangan ragu untuk mengkloning dan menjalankan repositori berikut: https://github.com/wjosset/ReactToOrientation
sumber
func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator)
tidak berhasil. Saya telah membuatnya bekerja menggunakanfunc viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator)
.Swift 4+: Saya menggunakan ini untuk desain keyboard lembut, dan untuk beberapa alasan
UIDevice.current.orientation.isLandscape
metode tersebut terus memberi tahu sayaPortrait
, jadi inilah yang saya gunakan sebagai gantinya:override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) if(size.width > self.view.frame.size.width){ //Landscape } else{ //Portrait } }
sumber
size
parameter yang disuntikkan di viewWillTransitionToSize: withCoordinator: Metode Anda tulis di atas. Ini akan mencerminkan ukuran persis tampilan Anda setelah transisi.Swift 4.2, RxSwift
Jika kita perlu memuat ulang collectionView.
NotificationCenter.default.rx.notification(UIDevice.orientationDidChangeNotification) .observeOn(MainScheduler.instance) .map { _ in } .bind(to: collectionView.rx.reloadData) .disposed(by: bag)
Cepat 4, RxSwift
Jika kita perlu memuat ulang collectionView.
NotificationCenter.default.rx.notification(NSNotification.Name.UIDeviceOrientationDidChange) .observeOn(MainScheduler.instance) .map { _ in } .bind(to: collectionView.rx.reloadData) .disposed(by: bag)
sumber
Saya percaya Jawaban yang benar adalah kombinasi dari kedua pendekatan:
viewWIllTransition(toSize:)
danNotificationCenter
'sUIDeviceOrientationDidChange
.viewWillTransition(toSize:)
memberi tahu Anda sebelum transisi.NotificationCenter
UIDeviceOrientationDidChange
memberi tahu Anda setelah .Anda harus sangat berhati-hati. Misalnya, di
UISplitViewController
saat berputar perangkat ke orientasi tertentu,DetailViewController
akan muncul dariUISplitViewController
'sviewcontrollers
array, dan didorong ke masterUINavigationController
. Jika Anda mencari pengontrol tampilan detail sebelum rotasi selesai, mungkin tidak ada dan crash.sumber
Jika Anda menggunakan versi Swift> = 3.0, ada beberapa pembaruan kode yang harus Anda terapkan seperti yang telah dikatakan orang lain. Jangan lupa untuk menelepon super:
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) // YOUR CODE OR FUNCTIONS CALL HERE }
Jika Anda berpikir untuk menggunakan StackView untuk gambar Anda, berhati-hatilah karena Anda dapat melakukan sesuatu seperti berikut:
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) if UIDevice.current.orientation.isLandscape { stackView.axis = .horizontal } else { stackView.axis = .vertical } // else }
Jika Anda menggunakan Interface Builder, jangan lupa untuk memilih kelas kustom untuk objek UIStackView ini, di bagian Identity Inspector di panel kanan. Kemudian buat saja (juga melalui Interface Builder) referensi IBOutlet ke instance UIStackView kustom:
@IBOutlet weak var stackView: MyStackView!
Ambil ide dan sesuaikan dengan kebutuhan Anda. Semoga ini bisa membantu Anda!
sumber
Cepat 4
Saya mengalami beberapa masalah kecil saat memperbarui tampilan ViewControllers menggunakan
UIDevice.current.orientation
, seperti memperbarui batasan sel tampilan tabel selama rotasi atau animasi subview.Alih-alih metode di atas, saat ini saya membandingkan ukuran transisi dengan ukuran tampilan pengontrol tampilan. Ini sepertinya cara yang tepat untuk pergi karena seseorang memiliki akses ke keduanya pada titik ini dalam kode:
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) print("Will Transition to size \(size) from super view size \(self.view.frame.size)") if (size.width > self.view.frame.size.width) { print("Landscape") } else { print("Portrait") } if (size.width != self.view.frame.size.width) { // Reload TableView to update cell's constraints. // Ensuring no dequeued cells have old constraints. DispatchQueue.main.async { self.tableView.reloadData() } } }
Output pada iPhone 6:
Will Transition to size (667.0, 375.0) from super view size (375.0, 667.0) Will Transition to size (375.0, 667.0) from super view size (667.0, 375.0)
sumber
Semua kontribusi sebelumnya baik-baik saja, tetapi sedikit catatan:
a) jika orientasi diatur dalam plist, hanya potret atau contoh, Anda akan tidak diberitahu melalui viewWillTransition
b) jika kita tetap perlu tahu apakah pengguna memiliki perangkat yang dirotasi, (misalnya permainan atau sejenisnya ..) kita hanya dapat menggunakan:
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.rotated), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
diuji di Xcode8, iOS11
sumber
Anda dapat menggunakan
viewWillTransition(to:with:)
dan memanfaatkananimate(alongsideTransition:completion:)
untuk mendapatkan orientasi antarmuka SETELAH transisi selesai. Anda hanya perlu mendefinisikan dan menerapkan protokol yang mirip dengan ini untuk memanfaatkan acara tersebut. Perhatikan bahwa kode ini digunakan untuk game SpriteKit dan penerapan spesifik Anda mungkin berbeda.protocol CanReceiveTransitionEvents { func viewWillTransition(to size: CGSize) func interfaceOrientationChanged(to orientation: UIInterfaceOrientation) }
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) guard let skView = self.view as? SKView, let canReceiveRotationEvents = skView.scene as? CanReceiveTransitionEvents else { return } coordinator.animate(alongsideTransition: nil) { _ in if let interfaceOrientation = UIApplication.shared.windows.first?.windowScene?.interfaceOrientation { canReceiveRotationEvents.interfaceOrientationChanged(to: interfaceOrientation) } } canReceiveRotationEvents.viewWillTransition(to: size) }
Anda bisa menyetel breakpoint dalam fungsi ini dan mengamati bahwa
interfaceOrientationChanged(to orientation: UIInterfaceOrientation)
selalu dipanggil setelahviewWillTransition(to size: CGSize)
dengan orientasi yang diperbarui.sumber
Untuk mendapatkan orientasi yang benar pada permulaan aplikasi, Anda harus memeriksanya
viewDidLayoutSubviews()
. Metode lain yang dijelaskan di sini tidak akan berfungsi.Berikut ini contoh cara melakukannya:
var mFirstStart = true override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() if (mFirstStart) { mFirstStart = false detectOrientation() } } func detectOrientation() { if UIDevice.current.orientation.isLandscape { print("Landscape") // do your stuff here for landscape } else { print("Portrait") // do your stuff here for portrait } } override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { detectOrientation() }
Ini akan selalu berfungsi, saat aplikasi pertama kali dimulai , dan jika berputar saat aplikasi berjalan .
sumber
Cara lain untuk mendeteksi orientasi perangkat adalah dengan fungsi traitCollectionDidChange (_ :). Sistem memanggil metode ini ketika lingkungan antarmuka iOS berubah.
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) //... }
Selanjutnya, Anda dapat menggunakan fungsi willTransition (to: with :) (yang dipanggil sebelum traitCollectionDidChange (_ :)), untuk mendapatkan informasi tepat sebelum orientasi diterapkan.
override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) { super.willTransition(to: newCollection, with: coordinator) //... }
sumber