SwiftUI: как условно представить ActionSheet только на iOS? - PullRequest
1 голос
/ 08 января 2020

Мне начал нравиться подход, когда я пишу кроссплатформенный код пользовательского интерфейса с SwiftUI. Приложение по-прежнему будет запускаться с собственным окном / контейнером, но иметь полностью кроссплатформенный интерфейс, управляемый SwiftUI. Для многих стандартных вещей, таких как list, navigationview и c, это очень полезно и отлично работает.

Проблема возникает с некоторыми платформенными c расширениями представления. Я хотел бы написать этот код в стиле платформы c, но не уверен, как это сделать для некоторых конкретных c случаев.

Во-первых, вот рабочий пример кроссплатформенного модификатора условного представления .

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 (ну, если быть точным, c, на любой не-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 возникает ошибка компиляции, поскольку API actionSheet недоступен в OSX. Что, действительно, так. Я хотел бы сделать так, чтобы вызов actionSheet был просто невозможен в OSX, но я не могу понять, как структурировать и условно скомпилировать мой код, чтобы это произошло.

вопрос, еще раз: как я могу структурировать этот код так, чтобы на iOS был представлен actionSheet, а на OSX он был бы неактивным?

1 Ответ

1 голос
/ 09 января 2020

Вы почти у цели. Вы бы нашли способ, если бы взглянули на сигнатуру функции .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))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...