SwiftUI — определение текущего устройства и ориентации

#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
            }
    }
}
 

Также обратите внимание, что ориентация устройства не равна ориентации интерфейса. Когда устройство перевернуто в портретном режиме, ориентация устройства книжная, но ориентация интерфейса также может быть альбомной.

Я думаю, что в вашем случае лучше полагаться на ориентацию интерфейса.