SwiftUI 和 MVVM:当视图模型更改“数据源”(`@Publish items`)本身时,如何为“列表元素更改”设置动画

Posted

技术标签:

【中文标题】SwiftUI 和 MVVM:当视图模型更改“数据源”(`@Publish items`)本身时,如何为“列表元素更改”设置动画【英文标题】:SwiftUI & MVVM: How to animate "list elements change" when view model changes the "data source" (`@Publish items`) itself 【发布时间】:2021-05-31 11:32:10 【问题描述】:

我对 SwfitUI 和 Combine 还比较陌生,所以也许我正在尝试做一些非常不正确的事情,但我只是看不出如何使用 SwiftUI 和 MVVM 来实现我的目标。 这是场景:

ViewModel 具有属性 @Published var items = [String]() 的类 具有 ForEach 的主视图 (HomeView) 显示其视图模型中的项目 HomeView 有一个@StateObject var viewModel: ViewModel HomeViewForEach 使用 viewModel 中的 items ViewModel 更改 items(在我的情况下核心数据更改) HomeViewForEach 会立即反映更改

这一切都有效,但我想做的是为ForEach 中的元素设置动画,因为viewModel.items 发生变化。

我能做的是将import SwiftUI 放入ViewModel 并使用withAnimation 包装新items 的设置。但这超出了 ViewModel 的用途,因为它现在直接引用了 UI 代码。

这里有一些代码:

struct HomeView: View 
    @StateObject var viewModel: ViewModel

    var body: some View 
         ForEach(items)  item in
            Text(item)
        
    

import SwiftUI // This should not be imported as it breaks MVVM patter

class ViewModel 
    @Published var items = [String]()

    func onItemsChanged(_ newItems: [String]) 
       withAnimation  // This works but will break MVVM patter
          items = newItems
       
    

是否有任何想法可以让 MVVM 满意并使用 SwiftUI?

【问题讨论】:

您的 View 可以使用 Toggle 在您的 ViewModel 上观察一些 bool 属性,例如切换(“”,isOn:$viewModel.someBoolProperty)。这样您就可以将工作转移到 VIEW 【参考方案1】:

将动画添加到包含您的视图项的容器中,如下所示

var body: some View 
  VStack                       // << container
     ForEach(items)  item in
        Text(item)
    
  
  .animation(.default)          // << animates changes in items

完整示例请参见下一篇文章:https://***.com/a/60893462/12299030、https://***.com/a/65776506/12299030、https://***.com/a/63364795/12299030。

【讨论】:

以上是关于SwiftUI 和 MVVM:当视图模型更改“数据源”(`@Publish items`)本身时,如何为“列表元素更改”设置动画的主要内容,如果未能解决你的问题,请参考以下文章

在 SwiftUI MVVM 中的子视图和父视图之间共享值

SwiftUI 在哪里加载 MVVM 中的数据

SwiftUI MVVM:父视图更新时重新初始化子视图模型

如何在 SwiftUI 中通过 ViewModel 传播模型更改?

手动更新 SwiftUI View

当视图模型@Published 更改时,SwiftUI 列表因“NSRangeException”而崩溃