首页 > 解决方案 > 在 SwiftUI 中为视图设置动画以在点击时向上滑动和隐藏

问题描述

我创建了一个从顶部显示横幅的横幅修改器。这动画效果很好。但是,当我点击以将其关闭时,它根本没有动画,即使点击手势动作已经withAnimation包裹它,它也会隐藏起来。

struct BannerModifier: ViewModifier {
    @Binding var model: BannerData?
    
    func body(content: Content) -> some View {
        content.overlay(
            Group {
                if model != nil {
                    VStack {
                        HStack(alignment: .firstTextBaseline) {
                            Image(systemName: "exclamationmark.triangle.fill")
                            VStack(alignment: .leading) {
                                Text(model?.title ?? "")
                                    .font(.headline)
                                if let message = model?.message {
                                    Text(message)
                                        .font(.footnote)
                                }
                            }
                        }
                        .padding()
                        .frame(minWidth: 0, maxWidth: .infinity)
                        .foregroundColor(.white)
                        .background(.red)
                        .cornerRadius(10)
                        .shadow(radius: 10)
                        Spacer()
                    }
                    .padding()
                    .animation(.easeInOut)
                    .transition(AnyTransition.move(edge: .top).combined(with: .opacity))
                    .onTapGesture {
                        withAnimation {
                            model = nil
                        }
                    }
                    .gesture(
                        DragGesture()
                            .onChanged { _ in
                                withAnimation {
                                    model = nil
                                }
                            }
                    )
                }
            }
        )
    }
}

struct BannerData: Identifiable {
    let id = UUID()
    let title: String
    let message: String?
}

在此处输入图像描述

在点击手势中,我清除了模型,但它没有动画。它只会立即隐藏。如何对其进行动画处理,使其向上滑动,这与向下滑动显示的方式相反?如果我也可以使拖动手势交互,这样我就可以像原生通知一样滑出它,那就太好了。

标签: iosswiftui

解决方案


从层次结构中删除视图始终由容器动画,因此要修复您的修改器,需要将其应用于.animation某个辅助容器(注意:Group实际上不是真正的容器)。

演示

这是更正的变体

struct BannerModifier: ViewModifier {
    @Binding var model: BannerData?
    
    func body(content: Content) -> some View {
        content.overlay(
            VStack {               // << holder container !!
                if model != nil {
                    VStack {
                        HStack(alignment: .firstTextBaseline) {
                            Image(systemName: "exclamationmark.triangle.fill")
                            VStack(alignment: .leading) {
                                Text(model?.title ?? "")
                                    .font(.headline)
                                if let message = model?.message {
                                    Text(message)
                                        .font(.footnote)
                                }
                            }
                        }
                        .padding()
                        .frame(minWidth: 0, maxWidth: .infinity)
                        .foregroundColor(.white)
                        .background(Color.red)
                        .cornerRadius(10)
                        .shadow(radius: 10)
                        Spacer()
                    }
                    .padding()
                    .transition(AnyTransition.move(edge: .top).combined(with: .opacity))
                    .onTapGesture {
                        withAnimation {
                            model = nil
                        }
                    }
                    .gesture(
                        DragGesture()
                            .onChanged { _ in
                                withAnimation {
                                    model = nil
                                }
                            }
                    )
                }
            }
            .animation(.easeInOut)         // << here !!
        )
    }
}

使用 Xcode 12.1 / iOS 14.1 和测试视图测试:

struct TestBannerModifier: View {
    @State var model: BannerData?
    var body: some View {
        VStack {
            Button("Test") { model = BannerData(title: "Error", message: "Fix It!")}
            Button("Reset") { model = nil }
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .modifier(BannerModifier(model: $model))
    }
}

推荐阅读