SwiftUI:如何仅在设备处于横向模式时启用 ScrollView?

Posted

技术标签:

【中文标题】SwiftUI:如何仅在设备处于横向模式时启用 ScrollView?【英文标题】:SwiftUI: How to enable ScrollView only when device is in landscape mode? 【发布时间】:2021-04-24 16:05:41 【问题描述】:

我正在尝试在应用程序未处于横向模式时禁用滚动视图,但我不知道如何在 SwiftUI 中执行此操作,是否有人对此有解决方案。当设备处于横向模式时,我尝试为轴属性添加空数组,但这不起作用:

ScrollView(axes, showsIndicators: false) 
    VStack(spacing: 10) 
        Text("Something 1")
        Text("Something 2")
        Text("Something 3")
        Text("Something 4")
        Text("Something 5")
    
.padding(.top, 10)

///...

private var axes: Axis.Set 
    return UIDevice.current.orientation.isLandscape ? [] : .vertical


【问题讨论】:

【参考方案1】:

Hacking With Swift 中有一些有用的代码可以检测 SwiftUI 中的设备方向变化:https://www.hackingwithswift.com/quick-start/swiftui/how-to-detect-device-rotation

但是,我不得不稍微改变它以获得可靠的第一个值。这是我最终得到的视图修饰符:

struct DeviceRotationViewModifier: ViewModifier 
    let action: (UIDeviceOrientation) -> Void
    
    func body(content: Content) -> some View 
        content
            .onAppear 
                action(UIDevice.current.orientation)
            
            .onReceive(NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification).dropFirst())  _ in
                action(UIDevice.current.orientation)
            
    


extension View 
    func onRotate(perform action: @escaping (UIDeviceOrientation) -> Void) -> some View 
        self.modifier(DeviceRotationViewModifier(action: action))
    

然后,在您的View 中,您可以有条件地显示ScrollView 或仅显示VStack,具体取决于此方向:

struct ContentView : View 
    @State private var orientation = UIDeviceOrientation.unknown
    
    @ViewBuilder var subView : some View 
        VStack(spacing: 10) 
            Text("Something 1")
            Text("Something 2")
            Text("Something 3")
            Text("Something 4")
            Text("Something 5")
        
    
    
    var body: some View 
        Group 
            if orientation.isLandscape 
                VStack 
                    subView
                    Spacer()
                
             else 
                ScrollView(.vertical, showsIndicators: false) 
                    subView
                
            
        
        .padding(.top, 10)
        .onRotate  newOrientation in
            orientation = newOrientation
        
    

【讨论】:

啊,是的,这是一个解决方案,我刚刚在 Hacking With Swift 上找到了这段代码,在我看到你回答之前一分钟,是的,这是一个解决方案,但我认为这有点 hacky,因为我将针对不同的方向显示完全不同的视图,如果有一种方法可以在横向方向禁用滚动视图会更好。但这完全可行,非常感谢您的帮助,我会尝试然后将其标记为一个好的解决方案。 我不会说这是一个完全不同的视图——这就是我将所有常见组件拆分为subView 的原因——它只是一个不同的容器。 在我重定向到选项卡栏中的某些不同视图后,当我在进入横向模式时使用此方法时遇到问题,一切都崩溃了,然后我让一切都像一个完全糟糕的视图一样向上移动,出于某种原因,我认为在重定向到其他视图时必须发送方向属性。当我回去使用 UIDevice.current.orientation.isLandscape 时,一切正常,... 由于某种原因,我发现当设备处于横向模式并且我只是午餐一个应用程序时,即使设备处于横向模式,方向属性也是错误的,我不知道这是为什么,你有什么线索吗? 我发现原始 Hacking with Swift 代码就是这种情况,但不是我的修改版本。【参考方案2】:

有一个禁用的选项,也许你可以使用:

struct ContentView : View 
    @State private var orientation = UIDeviceOrientation.unknown
    
    var body: some View 
        ScrollView(.vertical, showsIndicators: false) 
            VStack(spacing: 10) 
                Text("Something 1")
                Text("Something 2")
                Text("Something 3")
                Text("Something 4")
                Text("Something 5")
            
        .disabled(!orientation.isLandscape)
        .padding(.top, 10)
        .onRotate  newOrientation in
            orientation = newOrientation
        
    

【讨论】:

我认为这将禁用与滚动视图中的任何子元素的交互,对吧?对于 OP 来说,这可能是也可能不是问题 是的,这可能是个问题

以上是关于SwiftUI:如何仅在设备处于横向模式时启用 ScrollView?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 UIButton 上的代码解锁横向模式?

应用程序第一次处于纵向模式,如果设备处于横向模式

SwiftUI TabView 与 PageTabViewStyle 在设备上的横向与 safeArea 添加奇数前沿插图

使用 SwiftUI 将设备旋转到横向时出现导航栏

如何仅在横向模式下限制 j2me 应用程序

有没有办法强制 SwiftUI 中的横向模式仅用于某些视图?