Jak wyłączyć animację na liście, gdy zaobserwowano zmiany obiektu w SwiftUI?

15

Jak wyłączyć animację podczas zmiany danych modelu?

Mam następujący kod:

struct FormView: View {

    @ObservedObject var viewModel: FormViewModel

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

Za każdym razem zmiany modelu widoku Listsą aktualizowane za pomocą animacji.
Jak mogę to wyłączyć?
Próbowałem dodać, .animation(nil)ale to nie pomaga

0rt
źródło

Odpowiedzi:

1

Obejściem problemu, po którym Apple daje nam zmianę, aby to zrobić na Liście, jest wywołanie List.id (_ :) Zmienia wewnętrzny stan Listy i wymusza natychmiastowe odtworzenie Listy bez żadnej animacji. Aby uzyskać szczegółowe informacje, zobacz Lista przeładowań błędów animacji

To samo można zrobić na dowolnym widoku (func id () jest częścią protokołu View), ale musisz wiedzieć, że wszystkie zmienne stanu będą miały początkowy stan „domyślny”, więc używaj go ostrożnie. To samo, co „odtworzenie” Widoku.

Aby zrozumieć, jak to działa, zobacz https://swiftui-lab.com/swiftui-id/

użytkownik3441734
źródło
1

Rozwiązaniem, które znalazłem, jest dodanie unikalnego identyfikatora, który zmienia się za każdym razem, aby odbudować listę za każdym razem bez animacji. Zweryfikowano na iOS 13.4.

var body: some View {
    List {
        ForEach(viewModel.options) { option in
            Text(option.displayValue)
        }
    }
    .id(UUID()) // no animation
}
Burgler-dev
źródło
-3
  1. Nie ma potrzeby używania ForEach wewnątrz listy, jeśli nie korzystasz Sectionz nich. Więc zamiast:

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

    Do napisania wystarczy następujący kod:

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

    A także lepiej wiedzieć, że korzystanie z ForEach może powodować pewne problemy, na przykład: SwiftUI: czy można używać ForEach + ContextMenu?

  2. W przypadku, gdy użyjesz tylko ForEach()lub tylko List()+ .animation(nil)- musisz rozwiązać problem:

    Próbka 1:

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

    Próbka 2:

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

    Zostałem przetestowany zarówno na systemie macOS 10.15.2 (19C57) i działa idealnie.

  3. Ponadto można spróbować użyć .animation(nil)na Listi ForEachjedno i drugie. Nie próbowałem ... ale myślę, że to również da ci potrzebny efekt.

    List {
        ForEach(viewModel.options) { option in
            Text(option.displayValue)
        }.animation(nil)
    }.animation(nil)
    
Andrzej
źródło
.animation(nil)wydaje się nie mieć wpływu na 13.3, niestety
Fabian Streitel
@FabianStreitel Testowałem część 2 na macOS 10.15.2 (19C57) i działa idealnie.
Andrew
I testowałem wszystkie trzy warianty na iOS 13.3 (jak stwierdzono w moim komentarzu powyżej) i żaden z nich w ogóle nie zmienia zachowania listy. OP nie stwierdził niestety, czy tworzy aplikację na iOS czy macOS. Ale myślę, że informacja, że ​​nie działa na iOS, jest również ważna dla innych.
Fabian Streitel
Niedawno przetestowałem .animation(nil)przy użyciu Xcode 11.4 z iOS 13.4 i działa dla mnie.
Simen