簡體   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