Chcę dodać dwa obrazy do widoku pojedynczego obrazu (np. Jeden obraz poziomy i inny obraz pionowy), ale nie wiem, jak wykryć zmiany orientacji przy użyciu szybkich języków.
Wypróbowałem tę odpowiedź, ale wystarczy jedno zdjęcie
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
if UIDevice.currentDevice().orientation.isLandscape.boolValue {
print("Landscape")
} else {
print("Portrait")
}
}
Jestem nowy w rozwoju iOS, każda rada byłaby bardzo mile widziana!
Odpowiedzi:
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) } }
źródło
viewWillTransition
podklasyUIView
?.isFlat
. Jeśli chcesz tylko złapaćportrait
, sugeruję zmianę klauzuli else naelse if UIDevice.current.orientation.isPortrait
. Uwaga:.isFlat
może się zdarzyć zarówno w orientacji pionowej, jak i poziomej, aw przypadku just else {} zawsze będzie tam domyślnie (nawet jeśli jest to płaski krajobraz).Korzystanie NotificationCenter and 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") } }
Szybki 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") } }
źródło
viewWillTransition:
przewiduje, że zmiana nastąpi, podczas używaniaUIDeviceOrientationDidChange
jest wywoływana po zakończeniu zmiany.shouldAutorotate
jest ustawiony nafalse
. Jest to przydatne na ekranach, takich jak główny ekran aplikacji Aparat - orientacja jest zablokowana, ale przyciski mogą się obracać.Swift 3 Powyższy kod zaktualizowany:
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") } }
źródło
⚠️ Device Orientation! = Interface Orientation⚠️
Swift 5. * iOS14 i starsze
Naprawdę powinieneś zrobić różnicę między:
Istnieje wiele scenariuszy, w których te dwie wartości są niezgodne, na przykład:
W większości przypadków chciałbyś użyć orientacji interfejsu i możesz to uzyskać za pomocą okna:
private var windowInterfaceOrientation: UIInterfaceOrientation? { return UIApplication.shared.windows.first?.windowScene?.interfaceOrientation }
Jeśli chcesz również obsługiwać <iOS 13 (na przykład iOS 12), wykonaj następujące czynności:
private var windowInterfaceOrientation: UIInterfaceOrientation? { if #available(iOS 13.0, *) { return UIApplication.shared.windows.first?.windowScene?.interfaceOrientation } else { return UIApplication.shared.statusBarOrientation } }
Teraz musisz zdefiniować, gdzie zareagować na zmianę orientacji interfejsu okna. Można to zrobić na wiele sposobów, ale optymalnym rozwiązaniem jest zrobienie tego w ramach
willTransition(to newCollection: UITraitCollection
.Ta odziedziczona metoda UIViewController, którą można przesłonić, zostanie wyzwolona za każdym razem, gdy orientacja interfejsu zostanie zmieniona. W konsekwencji możesz wprowadzić wszystkie swoje modyfikacje w tym drugim.
Oto przykład rozwiązania :
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 } }
Wdrażając tę metodę, będziesz mógł reagować na każdą zmianę orientacji interfejsu. Pamiętaj jednak, że nie zostanie to uruchomione po otwarciu aplikacji, więc będziesz musiał również ręcznie zaktualizować interfejs w
viewWillAppear()
.Stworzyłem przykładowy projekt, który podkreśla różnicę między orientacją urządzenia a orientacją interfejsu. Dodatkowo pomoże Ci zrozumieć różne zachowania w zależności od tego, który etap cyklu życia zdecydujesz się zaktualizować swój interfejs użytkownika.
Zapraszam do sklonowania i uruchomienia następującego repozytorium: https://github.com/wjosset/ReactToOrientation
źródło
func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator)
nie zadziałało. Zrobiłem to za pomocąfunc viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator)
.Swift 4+: Używałem tego do projektowania miękkiej klawiatury iz jakiegoś powodu
UIDevice.current.orientation.isLandscape
metoda powtarzała mi, żePortrait
tak, więc oto, czego użyłem: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 } }
źródło
size
Parametrem, który jest wtryskiwany w viewWillTransitionToSize: withCoordinator: metoda napisałeś powyżej. Będzie to odzwierciedlać dokładny rozmiar, jaki będzie miał Twój widok po przejściu.Swift 4.2, RxSwift
Jeśli musimy ponownie załadować collectionView.
NotificationCenter.default.rx.notification(UIDevice.orientationDidChangeNotification) .observeOn(MainScheduler.instance) .map { _ in } .bind(to: collectionView.rx.reloadData) .disposed(by: bag)
Swift 4, RxSwift
Jeśli musimy ponownie załadować collectionView.
NotificationCenter.default.rx.notification(NSNotification.Name.UIDeviceOrientationDidChange) .observeOn(MainScheduler.instance) .map { _ in } .bind(to: collectionView.rx.reloadData) .disposed(by: bag)
źródło
Wierzę, że prawidłowa odpowiedź jest faktycznie połączenie obu podejść:
viewWIllTransition(toSize:)
aNotificationCenter
„sUIDeviceOrientationDidChange
.viewWillTransition(toSize:)
powiadamia Cię przed przejściem.NotificationCenter
UIDeviceOrientationDidChange
powiadomi Cię po .Musisz bardzo uważać. Na przykład,
UISplitViewController
gdy obraca się urządzenie do pewnych założeniach,DetailViewController
zostaje zdejmowana zUISplitViewController
„Sviewcontrollers
tablicy i nasunąć na MasterUINavigationController
. Jeśli zaczniesz szukać kontrolera widoku szczegółów przed zakończeniem obrotu, może on nie istnieć i ulec awarii.źródło
Jeśli używasz wersji Swift> = 3.0, istnieje kilka aktualizacji kodu, które musisz zastosować, jak powiedzieli już inni. Tylko nie zapomnij zadzwonić do super:
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) // YOUR CODE OR FUNCTIONS CALL HERE }
Jeśli myślisz o użyciu StackView do swoich obrazów, pamiętaj, że możesz wykonać następujące czynności:
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 }
Jeśli korzystasz z Interface Builder, nie zapomnij wybrać niestandardowej klasy dla tego obiektu UIStackView w sekcji Identity Inspector w prawym panelu. Następnie po prostu utwórz (również za pomocą Interface Builder) odwołanie IBOutlet do niestandardowej instancji UIStackView:
@IBOutlet weak var stackView: MyStackView!
Weź pomysł i dostosuj go do swoich potrzeb. Mam nadzieję, że to ci pomoże!
źródło
Szybki 4
Podczas aktualizowania widoku ViewControllers za pomocą
UIDevice.current.orientation
, takich jak aktualizowanie ograniczeń komórek widoku tabeli podczas obracania lub animacji widoków podrzędnych.Zamiast powyższych metod obecnie porównuję rozmiar przejścia z rozmiarem widoku kontrolerów widoku. Wydaje się, że jest to właściwy sposób, ponieważ w tym miejscu kodu mamy dostęp do obu:
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() } } }
Wyjście na 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)
źródło
Wszystkie poprzednie wpisy są w porządku, ale mała uwaga:
a) jeśli orientacja jest ustawiona w plist, tylko portret lub np Będziesz nie zgłoszone przez viewWillTransition
b) jeśli mimo wszystko potrzebujemy wiedzieć, czy użytkownik obrócił urządzenie (na przykład grę itp.), możemy użyć tylko:
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.rotated), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
testowany na Xcode8, iOS11
źródło
Możesz użyć
viewWillTransition(to:with:)
i dotknąć,animate(alongsideTransition:completion:)
aby uzyskać orientację interfejsu PO zakończeniu przejścia. Wystarczy zdefiniować i zaimplementować protokół podobny do tego, aby wykorzystać zdarzenie. Zwróć uwagę, że ten kod został użyty w grze SpriteKit, a Twoja konkretna implementacja może się różnić.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) }
Możesz ustawić punkty przerwania w tych funkcjach i obserwować, że
interfaceOrientationChanged(to orientation: UIInterfaceOrientation)
jest on zawsze wywoływany poviewWillTransition(to size: CGSize)
ze zaktualizowaną orientacją.źródło
Aby uzyskać prawidłową orientację podczas uruchamiania aplikacji , musisz to sprawdzić
viewDidLayoutSubviews()
. Inne opisane tutaj metody nie będą działać.Oto przykład, jak to zrobić:
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() }
Będzie to działać zawsze, przy pierwszym uruchomieniu aplikacji i podczas obracania, gdy aplikacja jest uruchomiona .
źródło
Innym sposobem wykrywania orientacji urządzeń jest użycie funkcji traitCollectionDidChange (_ :). System wywołuje tę metodę, gdy zmienia się środowisko interfejsu iOS.
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) //... }
Ponadto możesz użyć funkcji willTransition (to: with :) (która jest wywoływana przed traitCollectionDidChange (_ :)), aby uzyskać informacje tuż przed zastosowaniem orientacji.
override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) { super.willTransition(to: newCollection, with: coordinator) //... }
źródło