【问题标题】:show snack bar message in SwiftUI在 SwiftUI 中显示小吃店消息
【发布时间】:2020-05-22 02:29:04
【问题描述】:

有没有办法使用 SwiftUI 显示 HStack 之类的小吃店消息,该消息会在 (n) 秒后消失?

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

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

【问题讨论】:

    标签: swift swiftui snackbar


    【解决方案1】:

    您可以使用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))
        }
    }
    

    【讨论】:

    • 这是一个不错且简单的实现,但是,消息背景视图是半透明的,我尝试使用不透明度值更改所有颜色但无济于事,您是否知道如何使其背景具有纯色而不是半透明?
    • 我不明白。在上面的例子中,横幅背景是实心的,后面有阴影,当它出现在内容上时不是半透明的
    • 这是因为显示消息的视图位于 VStack 下
    • 如果我有一个只有 VStackZStack 的视图,当我在每个视图上使用 BannerModifier 时,如果我这样使用它就不会出现:ZStack {...}.banner(..)VStack{...}.banner(...),要使其正常工作,我必须始终使用 ZStack 进行设置,并且必须将以下行作为 ZStack 中的最后一个元素:EmptyView().banner(...),您可以直接在任何不需要使用这种解决方法的视图?
    • @JAHelia 解决您的问题的方法是 zIndex(_:)。默认情况下,zIndex 的值为 0(零)。您可以提供正值或负值来排列视图的重叠。链接:developer.apple.com/documentation/swiftui/group/3284926-zindex
    猜你喜欢
    • 2021-06-03
    • 2016-04-01
    • 2018-05-04
    • 2020-05-18
    • 2020-04-07
    • 2022-10-08
    • 2021-07-10
    • 1970-01-01
    • 2022-12-17
    相关资源
    最近更新 更多