【问题标题】:Insert, update and delete animations with ForEach in SwiftUI在 SwiftUI 中使用 ForEach 插入、更新和删除动画
【发布时间】:2020-08-12 15:17:51
【问题描述】:

我设法为ForEach 中显示的项目制作了一个漂亮的插入和删除动画(通过Row 上的.transition(...) 完成)。但遗憾的是,当我在观察到的数组中更新Item 的名称时,也会触发此动画。当然这是因为它实际上是一个新视图(您可以看到,因为调用了 RowonAppear())。

众所周知,推荐使用酷炫动画管理列表的方法是 List,但我认为很多人希望避免使用标准 UI 或此元素带来的限制。

一个工作的 SwiftUI 附加了示例 sn-p(使用 Xcode 11.4 构建)

那么问题来了:

对于保持相同位置的更新项目,是否有一种巧妙的方法来抑制动画(或有另一种动画)?是否有一种很酷的可能性可以“重用”该行并对其进行更新?

或者答案是“让我们等待下一次 WWDC,看看 Apple 是否会修复它……”? ;-)

干杯,
奥兰多????


编辑

当您可以区分编辑/添加/删除(例如,通过手动用户操作)时,bonky frenks 的回答实际上是一种好方法。只要items 数组在后台更新(例如,通过来自您的视图模型中的核心数据的同步更新),您不知道这是否是更新。但也许在这种情况下,答案是在视图模型中手动实现插入/更新/删除案例。


struct ContentView: View {

    @State var items: [Item] = [
        Item(name: "Tim"),
        Item(name: "Steve"),
        Item(name: "Bill")
    ]

    var body: some View {
        NavigationView {
            ScrollView {
                VStack {
                    ForEach(items, id: \.self) { item in
                        Row(name: item.name)
                    }
                }
            }
            .navigationBarItems(leading: AddButton, trailing: RenameButton)
        }
    }

    private var AddButton: some View {
        Button(action: {
            self.items.insert(Item(name: "Jeff"), at: 0)
        }) {
            Text("Add")
        }
    }

    private var RenameButton: some View {
        Button(action: {
            self.items[0].name = "Craigh"
        }) {
            Text("Rename first")
        }
    }
}

struct Row: View {

    @State var name: String

    var body: some View {
        HStack {
            Text(name)
            Spacer()
        }
        .padding()
        .animation(.spring())
        .transition(.move(edge: .leading))
    }
}

struct Item: Identifiable, Hashable {

    let id: UUID
    var name: String

    init(id: UUID = UUID(), name: String) {
        self.id = id
        self.name = name
    }
}

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

【问题讨论】:

    标签: swift listview animation foreach swiftui


    【解决方案1】:

    幸运的是,这实际上很容易做到。只需删除 Row 上的 .animation(.spring()),并将任何更改包装在 withAnimation(.spring()) { ... } 中。

    所以添加按钮将如下所示:

    private var AddButton: some View {
        Button(action: {
            withAnimation(.spring()) {
                self.items.insert(Item(name: "Jeff"), at: 0)
            }
        }) {
            Text("Add")
        }
    }
    

    您的 Row 将如下所示:

    struct Row: View {
    
        @State var name: String
    
        var body: some View {
            HStack {
                Text(name)
                Spacer()
            }
            .padding()
            .transition(.move(edge: .leading))
        }
    }
    

    【讨论】:

    • 感谢您的回答。你是对的,这解决了问题,因为在这个例子中我可以区分添加和编辑。但不幸的是,当 items 数组在后台更新时(例如,通过视图模型中的传入核心数据更新),这不是一个选项。由于我的问题不清楚,我会更新它...
    • 由于您对我未更新的问题的回答是正确的,我将接受它。另一方面,我希望后续会有一些替代方案;)再次感谢。
    • 据我所知,没有“干净”的方法可以做到这一点。您可以尝试添加一个抽象层,在该层中您将在后台更新的数据中添加didSet。然后使用withAnimation 设置用户界面中使用的数据。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-11-15
    • 2013-07-12
    • 1970-01-01
    • 2018-07-29
    • 2021-01-14
    • 2015-04-10
    • 1970-01-01
    相关资源
    最近更新 更多