如何在 SwiftUI 中制作“显示”式折叠/展开动画?

Joh*_*rug 65 animation swift swiftui

我想在 SwiftUI 中实现一个动画,“显示”视图的内容以启用展开/折叠功能。我想要折叠和展开的视图内容很复杂:它不仅仅是一个简单的框,而是动态高度和内容的视图层次结构,包括图像和文本。

我尝试过不同的选择,但没有达到预期的效果。通常发生的情况是,当我“展开”时,整个视图立即以 0% 不透明度显示,然后逐渐淡入,展开视图下的按钮同时向下移动。这就是当我使用if实际添加和删除视图的条件语句时发生的情况。所以这是有道理的。

然后我尝试使用frame修饰符:.frame(maxHeight: isExpanded ? .infinity : 0)。但这导致视图的内容被“压缩”而不是显示。

我制作了我想要的纸质原型:

纸质原型

关于如何实现这一目标有什么想法吗?

Jos*_*ach 22

像这样的东西可能会起作用。您可以在隐藏或不隐藏时将要公开的内容的高度修改为 0,nil以便它达到视图定义的高度。确保之后剪切视图,以便在未公开时内容在框架高度之外不可见。

struct ContentView: View {
    @State private var isDisclosed = false
    
    var body: some View {
        VStack {
            Button("Expand") {
                withAnimation {
                    isDisclosed.toggle()
                }
            }
            .buttonStyle(.plain)
            
            
            VStack {
                GroupBox {
                    Text("Hi")
                }
                
                GroupBox {
                    Text("More details here")
                }
            }
            .frame(height: isDisclosed ? nil : 0, alignment: .top)
            .clipped()
            
            HStack {
                Text("Cancel")
                Spacer()
                Text("Book")
            }
        }
        .frame(maxWidth: .infinity)
        .background(.thinMaterial)
        .padding()
    }
}
Run Code Online (Sandbox Code Playgroud)

不,这也不是为了符合您的设计。这只是为了提供创建动画的示例方法。

  • 杰出的!这正是我所需要的,非常感谢!我认为 `clipped` 和 `alignment: .top` 的组合是关键。 (2认同)
  • 如果文本跨越多行,这可能会出现问题。 (2认同)

Mey*_*sam 11

考虑使用DisclosureGroup. 以下代码应该是实现您的想法的好方法。

struct ContentView: View {
var body: some View {
    List(0...20, id: \.self) { idx in
        DisclosureGroup { 
            HStack {
                Image(systemName: "person.circle.fill")
                VStack(alignment: .leading) {
                    Text("ABC")
                    Text("Test Test")
                }
            }
            HStack {
                Image(systemName: "globe")
                VStack(alignment: .leading) {
                    Text("ABC")
                    Text("X Y Z")
                }
            }
            HStack {
                Image(systemName: "water.waves")
                VStack(alignment: .leading) {
                    Text("Bla Bla")
                    Text("123")
                }
            }
            HStack{
                Button("Cancel", role: .destructive) {}
                Spacer()
                Button("Book") {}
            }
        } label: { 
            HStack {
                Spacer()
                Text("Expand")
            }
        }
        
    }
}
Run Code Online (Sandbox Code Playgroud)

结果如下:

结果

我在 5 分钟内编写了这个代码。当然,设计可以根据您的需求进行优化,但核心应该是可以理解的。