繁体   English   中英

SwiftUI 多个垂直列表行动画不起作用

[英]SwiftUI multiple vertical lists row animations not working

突然间,我发现其中没有一个没有自动动画:

演示

没有用于插入、删除、重新排序等的动画。 ☹️ Id在转换之间是唯一持久的

问题 1

我怎样才能让它们按预期工作?

问题2

有没有一种简单的方法来制作动画来查看列表之间的转换? 就像在单个列表的部分之间移动一行。


解释:

假设我有三个列表,它们对单个数组的元素的不同状态进行分组:

extension Call {
    enum State: Equatable {
        case inProgress
        case accepted
        case rejected
    }
}

可观察的:

class CallManager: ObservableObject {
    @Published var calls: [Call]
    init(visits: [Call] = []) { self.calls = visits }
}

而 Call 是一个简单的 Identifiable:

struct Call: Identifiable & Equatable & Hashable {
    let id = UUID()
    var state: State
}

通过进行这些绑定,我已将所有列表绑定到核心calls数组:

extension CallManager {
    func bindingCalls(for state: Call.State) -> Binding<[Call]> {
        Binding<[Call]>(
            get: { self.calls.filter { $0.state == state } },
            set: { // TODO: Find a better way for this
                self.calls.removeAll(where: { $0.state == state })
                self.calls.append(contentsOf: $0)
            }
        )
    }

    var inProgress: Binding<[Call]> { bindingCalls(for: .inProgress) }
    var accepted: Binding<[Call]> { bindingCalls(for: .accepted) }
    var rejected: Binding<[Call]> { bindingCalls(for: .rejected) }
}

这是查看代码:

struct ContentView: View {

    @StateObject var visitManager =  CallManager(visits: [
        Call(state: .inProgress),
        Call(state: .accepted),
        Call(state: .accepted),
        Call(state: .inProgress),
        Call(state: .inProgress),
        Call(state: .rejected)
    ])

    var body: some View {
        HStack {
            List(visitManager.inProgress) { $call in
                CallView(call: $call)
            }

            List(visitManager.accepted) { $call in
                CallView(call: $call)
            }

            List(visitManager.rejected) { $call in
                CallView(call: $call)
            }
        }
    }
}

struct CallView: View & Identifiable {
    @Binding var call: Call
    var id: UUID { call.id }

    var body: some View {
        Text(call.id.uuidString.prefix(15))
            .foregroundColor(call.state.color)
            .onTapGesture(count: 2) { call.state = .rejected }
            .onTapGesture { call.state = .accepted }
    }
}

extension Call.State {
    var color: Color {
        switch self {
        case .inProgress: return .blue
        case .rejected: return .red
        case .accepted: return .green
        }
    }
}

您可以在列表视图上启用动画:

List(visitManager.inProgress) { $call in
    CallView(call: $call)
}
.animation(.default)

或者将更改包装在 withAnimation 块中:

.onTapGesture { withAnimation { call.state = .accepted } }

至于列之间的动画,您可以使用.matchedGeometryEffect获得类似的.matchedGeometryEffect afaik 它在 List 之间看起来总是有点易碎,为了使它看起来不错,你需要使用VStack (但随后失去了 List 视图的所有舒适性)。 例如:

import SwiftUI

extension Call {
    enum State: Equatable, CaseIterable {
        case inProgress
        case accepted
        case rejected
    }
}

class CallManager: ObservableObject {
    @Published var calls: [Call]
    init(visits: [Call] = []) { calls = visits }
}

struct Call: Identifiable & Equatable & Hashable {
    let id = UUID()
    var state: State
}

struct ContentView: View {
    @Namespace var items

    @StateObject var visitManager = CallManager(visits: [
        Call(state: .inProgress),
        Call(state: .accepted),
        Call(state: .accepted),
        Call(state: .inProgress),
        Call(state: .inProgress),
        Call(state: .rejected),
    ])

    var body: some View {
        HStack(alignment: .top) {
            ForEach(Call.State.allCases, id: \.self) { state in
                VStack {
                    List(visitManager.calls.filter { $0.state == state }) { call in
                        CallView(call: call)
                            .id(call.id)
                            .matchedGeometryEffect(id: call.id, in: items)
                            .onTapGesture {
                                if let idx = visitManager.calls.firstIndex(where: { $0.id == call.id }) {
                                    withAnimation {
                                        visitManager.calls[idx].state = .rejected
                                    }
                                }
                            }
                    }
                }
            }
        }
    }
}

struct CallView: View & Identifiable {
    var call: Call
    var id: UUID { call.id }

    var body: some View {
        Text(call.id.uuidString.prefix(15))
            .foregroundColor(call.state.color)
    }
}

extension Call.State {
    var color: Color {
        switch self {
        case .inProgress: return .blue
        case .rejected: return .red
        case .accepted: return .green
        }
    }
}

暂无
暂无

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

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