【问题标题】:SwiftUI: Animate changes in List without animating content changesSwiftUI:在不动画内容更改的情况下动画列表中的更改
【发布时间】:2020-01-29 17:23:59
【问题描述】:

我在 SwiftUI 中有一个简单的应用程序,它显示一个 List,每个项目都是一个带有两个 Text 元素的 VStack:

var body: some View {
    List(elements) { item in
        NavigationLink(destination: DetailView(item: item)) {
            VStack(alignment: .leading) {
                Text(item.name) 
                Text(self.distanceString(for: item.distance))
            }
        }
    }
    .animation(.default)
}

.animate() 在那里,因为我想在elements 数组更改时对列表的更改进行动画处理。不幸的是,SwiftUI 还会对内容的任何更改进行动画处理,从而导致奇怪的行为。例如,每个项目中的第二个Text 更新非常频繁,现在更新将在更新到新内容之前很快显示标签被截断(末尾带有...)。

那么当我更新列表的内容时如何防止这种奇怪的行为,但在列表中的元素发生变化时保留动画?

如果相关,我正在创建一个 watchOS 应用。

【问题讨论】:

    标签: swift swiftui watchos swiftui-list


    【解决方案1】:

    以下应该禁用行内部的动画

    VStack(alignment: .leading) {
        Text(item.name) 
        Text(self.distanceString(for: item.distance))
    }
    .animation(nil)
    

    【讨论】:

    • 我在 ForEach 中使用了 List,而句子 .animation(nil) 不适用于行
    【解决方案2】:

    @Asperi 的回答解决了我也遇到的问题(一如既往地支持他的回答)。

    我在使用以下内容为整个屏幕设置动画时遇到了问题:AnyTransition.asymmetric(insertion: .move(edge: .bottom), removal: .move(edge: .top))

    还有所有的 Text() 和 Button() 子视图,它们的动画方式也很奇怪,但并不那么美妙。在看到 Asperi 的回答后,我使用动画(nil)来解决这个问题。但是问题是我的按钮不再在选择时进行动画处理,以及我想要的其他动画。

    所以我添加了一个新的 State 变量来打开和关闭 VStack 的动画。默认情况下它们是关闭的,当视图在屏幕上显示动画后,我会在一小段延迟后启用它们:

    struct QuestionView : View {
        @State private var allowAnimations : Bool = false
    
        var body : some View {
            VStack(alignment: .leading, spacing: 6.0) {
                Text("Some Text")
    
                Button(action: {}, label:Text("A Button")
            }
            .animation(self.allowAnimations ? .default : nil)
            .onAppear() {
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.4) {
                    self.allowAnimations = true
                }
            }
        }
    }
    

    只需为与我有类似问题并需要在 Asperi 出色答案的基础上构建的任何人添加此内容。

    【讨论】:

    • .animation(:value:) 调用允许您将动画仅与值更改联系起来,而不是在神奇的秒数内禁用视图。
    • 最近也发现了这个@Beginner 不要告诉所有人,因为它有损我上面的出色答案;-)
    • 阴谋:点赞答案并发表评论,每个人都会获胜和学习。呵呵...虽然.default 作为停止重复动画的工具很高兴。
    【解决方案3】:

    感谢@Brett 提供延迟解决方案。我的代码在几个地方都需要它,所以我将它封装在一个 ViewModifier 中。

    只需将 .delayedAnimation() 添加到您的视图中。

    您可以传递默认值而不是一秒和默认动画的参数。

    import SwiftUI
    
    struct DelayedAnimation: ViewModifier {
      var delay: Double
      var animation: Animation
    
      @State private var animating = false
    
      func delayAnimation() {
        DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
          self.animating = true
        }
      }
    
      func body(content: Content) -> some View {
        content
          .animation(animating ? animation : nil)
          .onAppear(perform: delayAnimation)
      }
    }
    
    extension View {
      func delayedAnimation(delay: Double = 1.0, animation: Animation = .default) -> some View {
        self.modifier(DelayedAnimation(delay: delay, animation: animation))
      }
    }
    

    【讨论】:

    • 好一个吉姆! ?
    【解决方案4】:

    在我的情况下,上述任何情况都会导致奇怪的行为。解决方案是为触发元素数组变化的动作制作动画,而不是列表。例如:

    
    @State private var sortOrderAscending = true
    
    // Your list of elements with some sorting/filtering that depends on a state
    // In this case depends on sortOrderAscending
    var elements: [ElementType] {
        let sortedElements = Model.elements
        if (sortOrderAscending) {
            return sortedElements.sorted { $0.name < $1.name }
        } else {
            return sortedElements.sorted { $0.name > $1.name }
        }
    }
    
    var body: some View {
    
        // Your button or whatever that triggers the sorting/filtering
        // Here is where we use withAnimation
        Button("Sort by name") {
            withAnimation {
                sortOrderAscending.toggle()
            }
        }
    
        List(elements) { item in
            NavigationLink(destination: DetailView(item: item)) {
                VStack(alignment: .leading) {
                    Text(item.name) 
                }
            }
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 2014-03-08
      • 1970-01-01
      • 1970-01-01
      • 2022-01-14
      • 1970-01-01
      • 1970-01-01
      • 2017-04-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多