#ios #swiftui #uikit
#iOS #swiftui #uikit
Вопрос:
Я пытаюсь определить, когда устройство находится на iPad и в портретном режиме.
В настоящее время я использую UIDevice
API в UIKit и использую объект среды для просмотра изменений. Я использую решение, найденное здесь — определение текущего устройства и ориентации.
Однако orientationInfo.orientation
изначально значение всегда равно .portrait
значению, пока не будет повернуто в портретное положение, а затем обратно в альбомную ориентацию.
Поэтому при выполнении следующих действий для отображения FABView
struct HomeView: View {
@EnvironmentObject var orientationInfo: OrientationInfo
let isPhone = UIDevice.current.userInterfaceIdiom == .phone
var body: some View {
ZStack(alignment: .bottom) {
#if os(iOS)
if isPhone == false amp;amp; orientationInfo.orientation == .portrait {
FABView()
}
#endif
}
}
}
Представление загружается, когда iPad изначально находится в альбомной ориентации, но при переходе на книжную ориентацию и обратно в альбомную затем удаляется. Почему это происходит и как я могу убедиться, что представление не загружается при первой загрузке?
Полный код
struct HomeTab: View {
var body: some View {
NavigationView {
HomeView()
.environmentObject(OrientationInfo())
}
}
}
struct HomeView: View {
@EnvironmentObject var orientationInfo: OrientationInfo
let isPhone = UIDevice.current.userInterfaceIdiom == .phone
var body: some View {
ZStack(alignment: .bottom) {
#if os(iOS)
if isPhone == false amp;amp; orientationInfo.orientation == .portrait {
FABView()
}
#endif
}
}
}
final class OrientationInfo: ObservableObject {
enum Orientation {
case portrait
case landscape
}
@Published var orientation: Orientation
private var _observer: NSObjectProtocol?
init() {
// fairly arbitrary starting value for 'flat' orientations
if UIDevice.current.orientation.isLandscape {
self.orientation = .landscape
}
else {
self.orientation = .portrait
}
// unowned self because we unregister before self becomes invalid
_observer = NotificationCenter.default.addObserver(forName: UIDevice.orientationDidChangeNotification, object: nil, queue: nil) { [unowned self] note in
guard let device = note.object as? UIDevice else {
return
}
if device.orientation.isPortrait {
self.orientation = .portrait
}
else if device.orientation.isLandscape {
self.orientation = .landscape
}
}
}
deinit {
if let observer = _observer {
NotificationCenter.default.removeObserver(observer)
}
}
}
Ответ №1:
Вы можете использовать UIDevice.orientationDidChangeNotification
для обнаружения изменений ориентации, но вы не должны полагаться на это при запуске приложения.
UIDevice.current.orientation.isValidInterfaceOrientation
будет false в начале и, следовательно, оба
UIDevice.current.orientation.isLandscape
и
UIDevice.current.orientation.isPortrait
вернется false
.
Вместо этого вы можете использовать interfaceOrientation
сцену из первого окна:
struct ContentView: View {
@State private var isPortrait = false
var body: some View {
Text("isPortrait: (String(isPortrait))")
.onReceive(NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)) { _ in
guard let scene = UIApplication.shared.windows.first?.windowScene else { return }
self.isPortrait = scene.interfaceOrientation.isPortrait
}
}
}
Также обратите внимание, что ориентация устройства не равна ориентации интерфейса. Когда устройство перевернуто в портретном режиме, ориентация устройства книжная, но ориентация интерфейса также может быть альбомной.
Я думаю, что в вашем случае лучше полагаться на ориентацию интерфейса.