如何在使用 SwiftUI 的 .move 转换/动画时剪裁视图

3
我试图在一个视图中添加动画效果,使其看起来像是从另一个视图中打开的抽屉。这一切都很好,但如果第一个视图不是不透明的话,就会出现问题。似乎在动画开始时就可以看到动画视图。有没有办法剪辑它,使得它看起来是从底部视图的顶部增长出来的?
即使没有不透明度,如果你要从未被覆盖的地方进行动画,这也是一个问题(在第二个gif中演示)。

Animation example Other animation example

示例代码:

struct ContentView: View {
    @State private var showingSecondView: Bool = false
    

    var body: some View {
        VStack(spacing: 0) {
            Spacer()
            if showingSecondView {
                ZStack {
                    Color.green.opacity(0.25)
                    Text("Second View")
                }
                .frame(width: 300, height: 300)
                .transition(.move(edge: .bottom))
            }
            ZStack {
                Color.black.opacity(1)
                Text("First View")
            }
            .frame(width: 300, height: 300)
            Button("Animate In / Out") {
                showingSecondView.toggle()
            }
            .padding()
        }
        .animation(.easeInOut, value: showingSecondView)
      }
}
2个回答

4
可以通过剪辑“抽屉”准确容器来完成。这是一种可能的方法的演示。
在Xcode 13.2 / iOS 15.2(为了获得更好的演示效果,模拟器慢动画开启)进行测试。 demo
var body: some View {
    VStack(spacing: 0) {
        Spacer()
        VStack {
            if showingSecondView {
                ZStack {
                    Color.green.opacity(0.25)
                    Text("Second View")
                }
                .transition(.move(edge: .bottom))
            } else {
                Color.clear // << replacement for transition visibility
            }
        }
        .frame(width: 300, height: 300)
        .animation(.easeInOut, value: showingSecondView)  // << animate drawer !!
        .clipped()            // << clip drawer area
        
        ZStack {
            Color.black.opacity(0.2)
            Text("First View")
        }
        .frame(width: 300, height: 300)

        Button("Animate In / Out") {
            showingSecondView.toggle()
        }
        .padding()
    }
}

1
很好。像往常一样,对于SwiftUI,我希望我能理解它为什么起作用。 - Rob N
这太棒了,我遇到了同样的问题,你的解决方案非常出色。我能够在没有动画修饰符的情况下完成它。 - RPSM

2
这里有一个方法供您参考:
 struct ContentView: View {
    
    @State private var isSecondViewPresented: Bool = false

    var body: some View {
        
        VStack(spacing: 0) {
            Spacer()
            
            ZStack {
                Color.green.opacity(0.25).cornerRadius(20)
                Text("Second View")
            }
            .frame(width: 300, height: 300)
            .offset(y: isSecondViewPresented ? 0 : 300)
            .clipShape(RoundedRectangle(cornerRadius: 20))
            
            
            ZStack {
                Color.black.opacity(0.1).cornerRadius(20)
                Text("First View")
            }
            .frame(width: 300, height: 150)
            
            Button("Animate In / Out") {
                isSecondViewPresented.toggle()
            }
            .padding()
        }
        .animation(.easeInOut, value: isSecondViewPresented)
        
    }

}

enter image description here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接