在SwiftUI中显示小吃店消息

时间:2020-02-06 05:32:22

标签: swift swiftui snackbar

是否有一种方法可以显示HStack就像小吃店消息,该消息会在(n)秒后使用SwiftUI关闭?

我有以下结构,它是我的消息的容器:

struct MessageBuilder<Content>: View where Content: View {

    let content: () -> Content

    init(@ViewBuilder content: @escaping () -> Content) {
        self.content = content
    }

    var body: some View {
        content()
    }
}

我将MessageBuilder结构称为:

MessageBuilder {
            HStack {
                Image("MyImage")
                Text("Some Message")
            }
        }

我有两个问题:

(1)如何在屏幕顶部显示它,然后自动将其关闭(如SwiftMessages)?

(2)如何编写包装函数,例如在任何SwiftUI View上方显示消息。在基于Storyboard的项目中,我们将传递topViewController或rootViewController之类的内容,以便在其顶部显示UIView

1 个答案:

答案 0 :(得分:5)

您可以使用ViewModifier创建横幅视图,然后在SwiftUI中将其作为修饰符调用。 在修改器中使用ZStack在内容顶部显示横幅。 这是创建横幅并在视图顶部显示的简单示例

在您看来,您可以使用.banner(data: $bannerData, show: $showBanner)来展示横幅广告

struct BannerData {
        var title: String
        var detail: String
        var type: BannerType
    }

    enum BannerType {
        case info
        case warning
        case success
        case error

        var tintColor: Color {
            switch self {
            case .info:
                return Color(red: 67/255, green: 154/255, blue: 215/255)
            case .success:
                return Color.green
            case .warning:
                return Color.yellow
            case .error:
                return Color.red
            }
        }
    }

struct BannerModifier: ViewModifier {

    @Binding var data: BannerData
    @Binding var show: Bool


    @State var task: DispatchWorkItem?

    func body(content: Content) -> some View {
        ZStack {
            if show {
                VStack {
                    HStack {
                        VStack(alignment: .leading, spacing: 2) {
                            Text(data.title)
                                .bold()
                            Text(data.detail)
                                .font(Font.system(size: 15, weight: Font.Weight.light, design: Font.Design.default))
                        }
                        Spacer()
                    }
                    .foregroundColor(Color.white)
                    .padding(12)
                    .background(data.type.tintColor)
                    .cornerRadius(8)
                    .shadow(radius: 20)
                    Spacer()
                }
                .padding()
                .animation(.easeInOut(duration: 1.2))
                .transition(AnyTransition.move(edge: .top).combined(with: .opacity))

                .onTapGesture {
                    withAnimation {
                        self.show = false
                    }
                }.onAppear {
                    self.task = DispatchWorkItem {
                        withAnimation {
                            self.show = false
                        }
                    }
                    // Auto dismiss after 5 seconds, and cancel the task if view disappear before the auto dismiss
                    DispatchQueue.main.asyncAfter(deadline: .now() + 5, execute: self.task!)
                }
                .onDisappear {
                    self.task?.cancel()
                }
            }
            content
        }
    }
}

extension View {
    func banner(data: Binding<BannerData>, show: Binding<Bool>) -> some View {
        self.modifier(BannerModifier(data: data, show: show))
    }
}