【问题标题】:SwiftUI: How to enable ScrollView only when device is in landscape mode?SwiftUI:如何仅在设备处于横向模式时启用 ScrollView?
【发布时间】: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
}

【问题讨论】:

    标签: ios swift swiftui


    【解决方案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 来说,这可能是也可能不是问题
    • 是的,这可能是个问题
    猜你喜欢
    • 2011-06-28
    • 1970-01-01
    • 2019-10-30
    • 1970-01-01
    • 1970-01-01
    • 2011-06-13
    • 1970-01-01
    • 2015-06-23
    相关资源
    最近更新 更多