简体   繁体   English

SwiftUI - 确定电流设备和方向

[英]SwiftUI - Determining Current Device and Orientation

I am trying to detect when the device is on iPad and in Portrait.我试图检测设备何时在 iPad 和纵向上。

Currently I use the UIDevice API in UIKit and use an environment object to watch changes.目前我在 UIKit 中使用UIDevice API 并使用环境 object 来观察变化。 I use the solution found here - Determining Current Device and Orientation .我使用此处找到的解决方案 - Determining Current Device and Orientation

However the orientationInfo.orientation is initially always equal to .portrait until rotated into portrait and then back to landscape.然而, orientationInfo.orientation最初总是等于.portrait直到旋转成纵向然后再回到横向。

So when doing the following to display the FABView因此,当执行以下操作以显示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 && orientationInfo.orientation == .portrait {
            FABView()
          }
          #endif
      }
    }
}

The view is loaded when the iPad is initially in landscape, but when changing to portrait and back to landscape is then removed.当 iPad 最初处于横向时,将加载视图,但当更改为纵向并返回横向时,将被删除。 Why is this happening and how can I make sure the view isn't loaded on first load?为什么会发生这种情况,如何确保在第一次加载时未加载视图?

Full Code完整代码

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 && 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)
        }
    }
}

You can use UIDevice.orientationDidChangeNotification for detecting orientation changes but you shouldn't rely on it when the app starts.您可以使用UIDevice.orientationDidChangeNotification来检测方向更改,但在应用启动时不应依赖它。

UIDevice.current.orientation.isValidInterfaceOrientation will be false at the beginning and therefore both UIDevice.current.orientation.isValidInterfaceOrientation将在开始时为假,因此两者

  • UIDevice.current.orientation.isLandscape

and

  • UIDevice.current.orientation.isPortrait

will return false .将返回false

Instead you can use interfaceOrientation from the first window scene:相反,您可以使用第一个 window 场景中的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
            }
    }
}

Also note that device orientation is not equal to interface orientation .另请注意,设备方向不等于界面方向 When the device is upside down in portrait mode, device orientation is portrait but interface orientation can be landscape as well.当设备在纵向模式下倒置时,设备方向为纵向,但界面方向也可以为横向

I think it's better to rely on the interface orientation in your case.我认为在您的情况下最好依靠界面方向。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM