SwiftUI:如何仅在iOS上有条件地显示ActionSheet?

时间:2020-01-08 20:40:12

标签: swiftui

我开始喜欢使用SwiftUI编写跨平台UI代码的方法。该应用程序仍将使用本机窗口/容器启动,但具有完全跨平台的SwiftUI驱动的UI。对于许多标准的东西,例如列表,导航视图等,它非常有用并且可以正常工作。

问题出现在某些特定于平台的视图扩展上。我想以与平台无关的方式编写此代码,但不确定在某些特定情况下如何执行该代码。

首先,这是一个跨平台条件视图修饰符的工作示例。

import SwiftUI

struct DemoView: View {
    var body: some View {
        Text("Hello, demo!").padding()
            .modifier(iosBackground())
    }
}

struct iosBackground: ViewModifier {
    #if os(OSX)
    func body(content: Content) -> some View {
        content
    }
    #else
    func body(content: Content) -> some View {
        content.background(Color.blue)
    }
    #endif
}

iosBackground修饰符的作用是仅在iOS平台上应用视图修改(确切地说,在任何非OSX平台上,但在此示例中仅使用OSX和iOS) 。视图的OSX版本通过,而iOS版本返回修改后的视图。这个颜色示例当然是愚蠢且无用的,但是对于诸如填充之类的与布局相关的事情,这是一种非常实用的方法。

我的问题:我如何将相同的方法应用于诸如actionSheet之类的修饰符?这是我想做的事情:

struct DemoView: View {
    @State var showActionSheet = true
    var body: some View {
        Text("Hello, demo!").padding()
            .modifier(iosBackground())
            .actionSheet(isPresented: $showActionSheet) {
                ActionSheet(
                    title: Text("Actions"),
                    message: Text("Available actions"),
                    buttons: [
                        .cancel { },
                        .default(Text("Action")),
                        .destructive(Text("Delete"))
                    ]
                )
            }

    }
}

如果您尝试编译此代码,则在iOS上可以正常工作。在OSX上,它有一个编译错误,因为actionSheet API在OSX上不可用。的确如此。我想这样做,以使actionSheet调用在OSX上完全不起作用,但是我无法弄清楚如何构造和有条件地编译我的代码以使其实现。

问题再次出现:如何构造代码,以便在iOS上显示actionSheet,而在OSX上则是无操作?

1 个答案:

答案 0 :(得分:1)

您快到了。如果您查看.actionSheet的函数签名,就会找到解决方法。它返回不透明类型some View,这是几乎所有SwiftUI视图的返回类型。因此,也请查看文档:

/// Presents an action sheet.
///
/// - Parameters:
///     - isPresented: A `Binding` to whether the action sheet should be
///     shown.
///     - content: A closure returning the `ActionSheet` to present.
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, *)
@available(OSX, unavailable)
public func actionSheet(isPresented: Binding<Bool>, content: () -> ActionSheet) -> some View

话虽如此,您可以像将.background函数与内容一起使用一样使用它。因此,这是解决方案:

struct Sheet: ViewModifier {
    @Binding var presented: Bool

    func body(content: Content) -> some View {
        #if os(OSX)
        return content
        #else
        return content
            .actionSheet(isPresented: $presented) {
                ActionSheet(title: Text("Action Title"),
                            message: Text("Action Message"),
                            buttons: [.cancel(), .default(Text("Ok"))]
                )
        }
        #endif
    }
}

我刚刚将#if - #endif移到了函数体内,这需要明确地使用return关键字。您可以将其用作任何修饰符:

.modifier(Sheet(presented: $showActionSheet))