Как я могу анимировать отдельные строки в списке SwiftUI?

#list #animation #swiftui

Вопрос:

Я хочу показать список, где каждая строка отображается с анимацией непрозрачности и с увеличивающейся задержкой. Таким образом, 1-я строка должна появиться через 0,1 секунды, вторая-через 0,3 секунды, третья-через 0,5 секунды и т. Д.

Я попробовал следующее, но это не работает, так как все строки отображаются сразу и без анимации.

Любые советы будут очень признательны!

 struct GuideListView: View {

    @State var showListItems = false
    @State var animationDelay = 0.1
    // definitions of viewRouter, data etc.

    var body: some View {

        VStack {

            // other items, navLink etc.

            List {
                
                ForEach(data) { item in
                    
                    Button(action: {
                        // navigation action
                    }, label: {
                        RowView(item: item)
                    })
                    .opacity(showListItems ? 1 : 0)
                    .animation(Animation.easeOut(duration: 0.6).delay(animationDelay), value: showListItems)
                    .onAppear{
                        animationDelay = animationDelay   0.2
                    }

                } //: ForEach
          
            } //: List

        } //: VStack
        .onAppear{
            showListItems = true
    }
}
 

Ответ №1:

Ключ, по-видимому, использует индексы из цикла ForEach для установки времени появления анимации.

Ниже приведен код. Переключатель просто сбрасывает состояние, чтобы отобразить анимацию:

 struct GuideListView: View {
    let data = ["One", "Two", "Three", "Four"]
    @State var showListItems = false
    @State var animationDelay = 0.5
    // definitions of viewRouter, data etc.
    
    var body: some View {
        
        VStack {
            
            // other items, navLink etc.
            Toggle("Show List Items", isOn: $showListItems)

            List {
                
                ForEach(data.indices) { index in
                    
                    Button(action: {
                        // navigation action
                    }, label: {
                        Text(data[index])
                    })
                        .opacity(showListItems ? 1 : 0)
                        .animation(Animation.easeOut(duration: 0.6).delay(animationDelay * Double(index)), value: showListItems)

                } //: ForEach
                
            } //: List
            
        } //: VStack
    }
}
 

Комментарии:

1. Спасибо вам за вашу помощь. Это правильное решение. Я поиграл с ним еще немного, потому что он не работал при срабатывании с помощью onAppear {}, а не Toggle(). Оказывается, в onAppear{} нужна задержка, и все будет работать правильно. Более того, введение задержки также заставило мое оригинальное решение работать! Тем не менее, он показывает, что все строки анимируются одновременно, в то время как ваше решение создает желаемое поведение, когда строки анимируются одна за другой.

2. Я пропустил ту часть вашего первоначального вопроса, где вы сказали, что они не оживляют. Я зациклился на всем сразу и решил эту проблему. Иногда мне нужно читать внимательнее. Рад, что это исправлено!

3. Да, похоже, это решение. К сожалению, с тех пор я обнаружил, что использование индексов действительно испортило фильтрацию данных, и Xcode бросал мне ограничения. Но это уже другой вопрос. На данный момент я придерживаюсь анимации всего списка сразу.

4. Я с нетерпением буду ждать этого вопроса. Я не уверен, что это действительно проблема. Возможно, это вопрос порядка вещей.