繁体   English   中英

在 SwiftUI 中插入/移除 animation

[英]Insertion/Removal animation in SwiftUI

我正在尝试实现此 animation 以在VStack中插入元素,所有元素向下移动以为新元素创建空间,然后从右向左插入新元素。 下面的代码按照我的描述进行插入,但是如何使它也可以用于移除,animation 应该类似,元素被完全移除(向右),然后其他元素向上移动)

struct ContentView: View {
    
    @State var show = false
    
    var body: some View {
        VStack {
            
            show ? Rectangle().frame(width: 100, height: 100, alignment: .center)
                .animation(Animation.easeIn(duration: 0.5).delay(1))
                .transition(.move(edge: .trailing)): nil
            
            Rectangle().frame(width: 100, height: 100, alignment: .center)
            Rectangle().frame(width: 100, height: 100, alignment: .center)
            Rectangle().frame(width: 100, height: 100, alignment: .center)
            Rectangle().frame(width: 100, height: 100, alignment: .center)
            
            Button("Add") {
                show.toggle()
            }
            Spacer()
            
        }.animation(Animation.easeIn(duration: 0.5))
    }
}

在此处输入图像描述

我不确定您的最终结果到底应该是什么,而且我提出的解决方案并不是真正的“通用”,但它至少应该为您提供一个起点。

struct ContentView: View {
    
    @State var show = false
    @State var showPlaceholder = false
    
    // The total animation duration will be twice as long as this value
    private var animationDuration: TimeInterval = 0.5
    
    var body: some View {
        VStack {
            
            ZStack {
                if showPlaceholder {
                    Color.white.opacity(0.0)
                        .zIndex(1)
                        .frame(width: 100, height: 100)
                }
                if show {
                    Rectangle()
                        .zIndex(2)
                        .frame(width: 100, height: 100, alignment: .center)
                        .animation(Animation.easeIn(duration: animationDuration))
                    .transition(.move(edge: .trailing))
                }
            }
            
            Rectangle().frame(width: 100, height: 100, alignment: .center)
            Rectangle().frame(width: 100, height: 100, alignment: .center)
            Rectangle().frame(width: 100, height: 100, alignment: .center)
            Rectangle().frame(width: 100, height: 100, alignment: .center)
            
            Button("Add") {
                if show {
                    showPlaceholder(for: animationDuration)
                    show = false
                }
                else {
                    showPlaceholder(for: animationDuration) {
                        show = true
                    }
                }
            }
            Spacer()
            
        }.animation(Animation.easeIn(duration: animationDuration))
    }
    
    private func showPlaceholder(for timeInterval: TimeInterval, completion: (() -> Void)? = nil) {
        showPlaceholder = true
        Timer.scheduledTimer(withTimeInterval: timeInterval, repeats: false) { (_) in
            showPlaceholder = false
            completion?()
        }
    }
}

如果你有那么多Rectangle() ,你应该使用ForEach 这将使添加和删除它们变得更加容易,因为您只需appendremoveLast即可更改显示的数量。

这是我所做的:

  1. 创建一个表示Rectangle的新结构
  2. added的属性将控制是否显示Rectangle
  3. 定义将显示给用户的RectangleInfo数组
  4. 使用ForEach遍历rectangles
  5. 您可以使用offset代替transition来更好地控制 animation。

设置好 UI 后,就该制作动画了:

  1. 首先 append 一个矩形,为它腾出空间
  2. added后,设置为 true 以便它滑入
  3. 设置added到 false 以将其滑出
  4. 一旦滑出,将其从阵列中移除并移除空间。
struct RectangleInfo: Identifiable { /// 1.
    let id = UUID()
    var added = true /// 2.
}

struct ContentView: View {
    
    @State var rectangles = [ /// 3.
        RectangleInfo(),
        RectangleInfo(),
        RectangleInfo()
    ]
    
    let animationDuration = 0.5
    
    var body: some View {
        VStack {
            
            ForEach(rectangles) { rectangle in /// 4.
                Rectangle().frame(width: 100, height: 100, alignment: .center)
                    .offset(x: rectangle.added ? 0 : 200, y: 0) /// 5.
            }
            
            Button("Add") {
                rectangles.append(RectangleInfo(added: false)) /// 6.
                DispatchQueue.main.asyncAfter(deadline: .now() + animationDuration) {
                    rectangles[rectangles.count - 1].added = true /// 7.
                }
            }
            Button("Remove") {
                rectangles[rectangles.count - 1].added = false /// 8.
                DispatchQueue.main.asyncAfter(deadline: .now() + animationDuration) {
                    rectangles.removeLast() /// 9.
                }
            }
            
            Spacer()
            
        }.animation(Animation.easeIn(duration: animationDuration))
    }
}

结果:

矩形垂直堆叠,底部有添加和删除按钮。按添加首先腾出空间,然后将矩形滑入。按删除首先删除矩形,然后删除空间。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM