在 SwiftUI 中将视图添加到层​​次结构时如何动画过渡

Posted

技术标签:

【中文标题】在 SwiftUI 中将视图添加到层​​次结构时如何动画过渡【英文标题】:How to animate transition when adding view to hierarchy in SwiftUI 【发布时间】:2020-10-16 17:33:03 【问题描述】:

我正在尝试构建“弹出框”视图的叠加层并为进出动画过渡。转出有效,但转入无效 - 添加弹出视图时,它会突然出现(错误),但删除弹出视图时,它会向右滑出(正确)。在此代码中将弹出框添加到视图层次结构时,如何使弹出框滑入(从右侧)?

ios 14 中的完整功能代码。

import SwiftUI

struct ContentView: View 
    
    var body: some View 
        Popovers()
    


struct Popovers : View 
    
    @State var popovers : [AnyView] = []
    
    var body : some View 
        Button("Add a view ...") 
            withAnimation 
                popovers += [new()]
            
        
        .blur(radius: 0 < popovers.count ? 8 : 0)
        .overlay(ZStack 
            ForEach(0..<self.popovers.count, id: \.self)  i in
                popovers[i]
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                    .blur(radius: (i+1) < popovers.count ? 8 : 0)
                    .transition(.move(edge: .trailing)) // works only when popover is removed
            
        )
    
    
    func new() -> AnyView 
        let popover = popovers.count
        
        return AnyView.init(
            VStack(spacing: 64) 
                
                Button("Close") 
                    withAnimation 
                        _ = popovers.removeLast()
                    
                
                .font(.largeTitle)
                .padding()

                Button("Add") 
                    withAnimation 
                        popovers += [new()]
                    
                
                .font(.largeTitle)
                .padding()

                Text("This is popover #\(popover)")
                    .font(.title)
                    .foregroundColor(.white)
                    .fixedSize()
                
            
            .background(Color.init(hue: 0.65-(Double(3*popover)/100.0), saturation: 0.3, brightness: 0.9).opacity(0.98))
        )
    
    


struct ContentView_Previews: PreviewProvider 
    static var previews: some View 
        ContentView()
    


extension View 
    var asAnyView : AnyView 
        AnyView(self)
    

【问题讨论】:

【参考方案1】:

解决方案是向容器添加动画。使用 Xcode 12 / iOS 14 测试。

struct Popovers : View 
    
    @State var popovers : [AnyView] = []
    
    var body : some View 
        Button("Add a view ...") 
            withAnimation 
                popovers += [new()]
            
        
        .blur(radius: 0 < popovers.count ? 8 : 0)
        .overlay(ZStack 
            ForEach(0..<self.popovers.count, id: \.self)  i in
                popovers[i]
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                    .blur(radius: (i+1) < popovers.count ? 8 : 0)
                    .transition(.move(edge: .trailing))
            
        .animation(.default))    // << add animation to container
    
    
    func new() -> AnyView 
        let popover = popovers.count
        
        return AnyView.init(
            VStack(spacing: 64) 
                
                Button("Close") 
                            _ = popovers.removeLast()
                
                .font(.largeTitle)
                .padding()

                Button("Add") 
                            popovers += [new()]
                
                .font(.largeTitle)
                .padding()

                Text("This is popover #\(popover)")
                    .font(.title)
                    .foregroundColor(.white)
                    .fixedSize()
                
            
            .background(Color.init(hue: 0.65-(Double(3*popover)/100.0), saturation: 0.3, brightness: 0.9).opacity(0.98))
        )
    
    

【讨论】:

效果很好,但为什么它现在可以工作 - 为什么它可以用于转出但不能转入?

以上是关于在 SwiftUI 中将视图添加到层​​次结构时如何动画过渡的主要内容,如果未能解决你的问题,请参考以下文章

如何在 SwiftUI 中将滚动视图添加到屏幕的特定部分? [复制]

是否可以在 SwiftUI 中将 Button<Text> 添加到 Text 中?

自定义交互式演示转换

在 SwiftUI 中将绑定传递给导航堆栈中每个视图的最佳方法是啥

如何在 SwiftUI 中将模糊效果作为背景?

如何在 SwiftUI 中将视图的背景设置为灰色?