簡體   English   中英

屬性更改 SwiftUI 的動畫視圖

[英]Animate view on property change SwiftUI

我有意見

struct CellView: View {
    @Binding var color: Int
    @State var padding : Length = 10
    let colors = [Color.yellow, Color.red, Color.blue, Color.green]

    var body: some View {
        colors[color]
            .cornerRadius(20)
            .padding(padding)
            .animation(.spring())
    }
}

我希望它在屬性color更改時具有填充動畫。 我想動畫填充從 10 到 0。

我試過使用onAppear

    ...onAppear {
      self.padding = 0
    }

但是當視圖出現時它只工作一次(按預期),我想每次當屬性color改變時都這樣做。 基本上,每次color屬性更改時,我都希望將 padding 從100 你能告訴我是否有辦法做到這一點?

正如您在另一個答案中注意到的那樣,您無法從body內部更新狀態。 你也不能使用didSet@Binding (至少在測試版4)與方式,您可以@State

我能想出的最佳解決方案是使用BindableObjectsink/onReceive以便在每次color更改時更新padding 我還需要添加延遲以使填充動畫完成。

class IndexBinding: BindableObject {
    let willChange = PassthroughSubject<Void, Never>()
    var index: Int = 0 {
        didSet {
            self.willChange.send()
        }
    }
}

struct ParentView: View {
    @State var index = IndexBinding()
    var body: some View {
        CellView(index: self.index)
            .gesture(TapGesture().onEnded { _ in
                self.index.index += 1
            })
    }
}

struct CellView: View {

    @ObjectBinding var index: IndexBinding
    @State private var padding: CGFloat = 0.0

    var body: some View {
            Color.red
                .cornerRadius(20.0)
                .padding(self.padding + 20.0)
                .animation(.spring())
                .onReceive(self.index.willChange) {
                    self.padding = 10.0
                    DispatchQueue.main.asyncAfter(deadline: .now() + 0.35) {
                        self.padding = 0.0
                    }
                }
    }
}


此示例不會在 Beta 4 上的 Xcode 畫布中設置動畫。在模擬器或設備上運行它。

從 Xcode 12 開始,Swift 5

實現預期結果的一種方法是將當前選定的索引移動到ObservableObject

final class CellViewModel: ObservableObject {
    @Published var index: Int
    init(index: Int = 0) {
        self.index = index
    }
}

然后,您的CellView可以使用.onReceive(_:)修飾符對索引的這種變化做出反應; 使用$前綴訪問由@Published屬性包裝器提供的Publisher者。

然后,您可以使用此修飾符提供的閉包來更新填充並為更改設置動畫。

struct CellView: View {
    @ObservedObject var viewModel: CellViewModel
    @State private var padding : CGFloat = 10
    let colors: [Color] = [.yellow, .red, .blue, .green]
    
    var body: some View {
        colors[viewModel.index]
            .cornerRadius(20)
            .padding(padding)
            .onReceive(viewModel.$index) { _ in
                padding = 10
                withAnimation(.spring()) {
                    padding = 0
                }
            }
    }
}

這是用於演示的示例父視圖:

struct ParentView: View {
    let viewModel: CellViewModel
    
    var body: some View {
        VStack {
            CellView(viewModel: viewModel)
                .frame(width: 200, height: 200)
            HStack {
                ForEach(0..<4) { i in
                    Button(action: { viewModel.index = i }) {
                        Text("\(i)")
                            .padding()
                            .frame(maxWidth: .infinity)
                            .background(Color(.secondarySystemFill))
                    }
                }
            }
        }
    }
}

請注意,此處的 Parent 不需要其 viewModel 屬性為@ObservedObject

您可以使用 Computed Properties 使其正常工作。 下面的代碼是如何完成的示例。

import SwiftUI

struct ColorChanges: View {
    @State var color: Float = 0

    var body: some View {
        VStack {
            Slider(value: $color, from: 0, through: 3, by: 1)
            CellView(color: Int(color))
        }
    }
}

struct CellView: View {
    var color: Int
    @State var colorOld: Int = 0

    var padding: CGFloat {
        if color != colorOld {
            colorOld = color
            return 40
        } else {
            return 0
        }
    }

    let colors = [Color.yellow, Color.red, Color.blue, Color.green]

    var body: some View {
        colors[color]
            .cornerRadius(20)
            .padding(padding)
            .animation(.spring())
    }
}

每當顏色屬性發生單個增量更改時,這將在 10 和 0 之間切換填充

padding =  color % 2 == 0 ? 10 : 0

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM