【问题标题】:How update a SwiftUI List without animation如何在没有动画的情况下更新 SwiftUI 列表
【发布时间】:2019-06-10 21:03:44
【问题描述】:

我想更新一个没有任何插入动画的 SwiftUI 列表。 我的List 正在从@EnvironmentObject 获取数据 我已经尝试将List 本身和PassthroughSubject.send() 包装在withAnimation(.empty) 块中,但这没有帮助。

一个非常非常肮脏的解决方法是调用UIView.setAnimationsEnabled(false)(是的,UIKit 对 SwiftUI 有影响),但必须有类似 SwiftUI 的方式来设置自定义插入动画。

【问题讨论】:

  • 问题是,如果这个功能已经存在并且我找不到它。
  • 能分享一下代码吗?

标签: ios swift swiftui


【解决方案1】:

这可行,只需将.id(UUID()) 放在列表末尾

List {
    // for each etc
}.id(UUID())

有点像 UIKit 的 reloadData

【讨论】:

  • 这样就达到了想要的效果,但是……为什么呢?
  • 它似乎只是导致它在每次更新时重新绘制整个列表(因为 ID 总是在变化,因为它每次都是新的 UUID),所以这看起来很像一个 hack。跨度>
  • SwiftUI 通常在当前列表和新列表之间做一个 DIFF 来确定插入和删除的行,但是每次它认为它有一个新列表时都会设置一个新的 UUID,所以不必费心去做差异。
【解决方案2】:

虽然 DogCoffee 提供的答案有效,但这样做的效率很低。有时我们确实不得不通过低效来强迫系统做我们想做的事情。对于 SwiftUI 中的隐式动画,有更好的方法来禁用它们。

使用 SwiftUI 中的Transaction 机制,我们可以定义一个可以应用于任何视图的扩展。这将禁用视图和所有子视图的动画。

对于列表视图示例,这避免了将列表中的所有数据替换为新的但相同的副本。

extension View {
     
    func animationsDisabled() -> some View {
        return self.transaction { (tx: inout Transaction) in
            tx.disablesAnimations = true
            tx.animation = nil
        }.animation(nil)
    }
}

尝试将此扩展应用到您的列表或包含视图的父级。您可能需要进行试验才能找到理想的视图。

List {
    // for each etc
}.animationsDisabled()

【讨论】:

  • 我用那个:List { ... }.animation(nil)。我正在使用 Xcode 11.5
【解决方案3】:

在 tvOS 上这对我有用:

List {
    ...
}
    .animation(.none)

【讨论】:

  • 与之前回答的类似变体相比,这种语法有什么好处?例如,正如 Gene Z. Ragan 所建议的那样,为什么有人更喜欢 .animation(nil)
  • @Gert Arnold - 我确实尝试过代码,它在 tvOS 中对我有用,通常我会发送大量代码和完整工作的示例,但有人告诉我,寻求一个班轮的用户与可能(我也喜欢简短的简短答案,所以我决定自己尝试提供一个),我会修复我的答案以澄清它
  • @Jeremy Caney - 我更喜欢控制代码并使用苹果的属性和值,因此如果未来的 SwiftUI 版本将更改 API,我可以收到通知,只需设置为 nil(无值)即可如果该选项(无)已更改、已弃用或不再受支持,编译器会通知我,如果该选项已消失,则使用 nil 可能会导致不可预知的行为
【解决方案4】:

【讨论】:

  • 恐怕将 .animation(nil) 设置为既不是 List 本身也不是其中的项目会在新项目加载并更新到列表时使“折叠”动画消失。
  • 我认为他的意思是 .animation(.none)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-08
  • 1970-01-01
  • 2016-04-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多