简体   繁体   中英

How to disable animation in list when observed object changes in SwiftUI?

How do I disable animation when view model data changes?

I have the following code:

struct FormView: View {

    @ObservedObject var viewModel: FormViewModel

    var body: some View {
        List {
            ForEach(viewModel.options) { option in
                Text(option.displayValue)
            }
        }
    }
}

Every time view model changes List gets updated with animation.
How can I disable it?
I tried adding .animation(nil) but it does not help

The solution I found is to add a unique identifier that changes every time, so it will rebuild the list every time without animation. Verified on iOS 13.4.

var body: some View {
    List {
        ForEach(viewModel.options) { option in
            Text(option.displayValue)
        }
    }
    .id(UUID()) // no animation
}

我认为最好的解决方案是将 UUID() 设置为动画值输入:

        .animation(nil, value: UUID())

The workaround till Apple give us a change to do it on List is call List.id(_:) It change the internal state of List and force the List to recreate immediatly, without any animation. For details see List reload animation glitches

The same could be done on any View (func id() is part of View protocol), but you have to know that all state variables will have initial "default" state, so use it carefully. It is the same like "recreate" the View.

To be able to understand how it works, see https://swiftui-lab.com/swiftui-id/

@available(macOS 10.15, *)
public extension View {
    func animationDisable() -> some View {
        self.animation(nil, value: UUID())
    }
}
  1. There is no need to use ForEach inside of List in case of you do not use Section 's. So instead of:

     List { ForEach(viewModel.options) { option in Text(option.displayValue) }) }

    The following code is enough to write:

     List(viewModel.options) { option in Text(option.displayValue) }

    And also better to know that using of ForEach can create some problems, as example: SwiftUI: is it possible to use ForEach + ContextMenu?

  2. In case of you will use only ForEach() or only List() + .animation(nil) -- must resolve your problem:

    Sample 1:

     ForEach(viewModel.options) { option in Text(option.displayValue) }.animation(nil)

    Sample 2:

     List(viewModel.options) { option in Text(option.displayValue) }.animation(nil)

    I have been tested both on macOS 10.15.2 (19C57) and it's works perfectly.

  3. Also you can try to use .animation(nil) on List and ForEach both. I didn't try... but I think this also will give you effect needed.

     List { ForEach(viewModel.options) { option in Text(option.displayValue) }.animation(nil) }.animation(nil)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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