Вставляйте, обновляйте и удаляйте анимации с помощью ForEach в SwiftUI - PullRequest
1 голос
/ 28 апреля 2020

Мне удалось получить хорошую вставку и удаление анимации для элементов, отображаемых в ForEach (выполняется через .transition(...) на Row). Но, к сожалению, эта анимация также запускается, когда я просто обновляю имя Item в наблюдаемом массиве. Конечно, это потому, что на самом деле это новое представление (вы можете видеть это, поскольку вызывается onAppear() из Row).

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

Прилагается рабочий пример SwiftUI , пример (Сборка с Xcode 11.4 )

Итак, вопрос:

Есть ли умный способ подавить анимацию (или иметь другую) для только что обновленных элементов, которые будут сохранять ту же позицию? Есть ли классная возможность «повторно использовать» строку и просто обновить ее?

Или ответ «Давайте подождем следующую WWD C и посмотрим, исправит ли ее Apple ... "? ; -)

Приветствия,
Орландо ?


Редактировать

Бонки Фронкс ответ на самом деле хороший подход, когда вы можете различить guish между редактированием / добавлением / удалением (например, ручными действиями пользователя). Как только массив items обновляется в фоновом режиме (например, с помощью синхронизированных обновлений, поступающих из Core Data в вашей модели представления), вы не знаете, является ли это обновлением или нет. Но, возможно, в этом случае ответ будет заключаться в том, чтобы вручную реализовать случаи вставки / обновления / удаления в модели представления.


struct ContentView: View {

    @State var items: [Item] = [
        Item(name: "Tim"),
        Item(name: "Steve"),
        Item(name: "Bill")
    ]

    var body: some View {
        NavigationView {
            ScrollView {
                VStack {
                    ForEach(items, id: \.self) { item in
                        Row(name: item.name)
                    }
                }
            }
            .navigationBarItems(leading: AddButton, trailing: RenameButton)
        }
    }

    private var AddButton: some View {
        Button(action: {
            self.items.insert(Item(name: "Jeff"), at: 0)
        }) {
            Text("Add")
        }
    }

    private var RenameButton: some View {
        Button(action: {
            self.items[0].name = "Craigh"
        }) {
            Text("Rename first")
        }
    }
}

struct Row: View {

    @State var name: String

    var body: some View {
        HStack {
            Text(name)
            Spacer()
        }
        .padding()
        .animation(.spring())
        .transition(.move(edge: .leading))
    }
}

struct Item: Identifiable, Hashable {

    let id: UUID
    var name: String

    init(id: UUID = UUID(), name: String) {
        self.id = id
        self.name = name
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

1 Ответ

1 голос
/ 28 апреля 2020

К счастью, это действительно легко сделать. Просто удалите .animation(.spring()) в своей строке и оберните все изменения в withAnimation(.spring()) { ... }.

Так кнопка добавления будет выглядеть так:

private var AddButton: some View {
    Button(action: {
        withAnimation(.spring()) {
            self.items.insert(Item(name: "Jeff"), at: 0)
        }
    }) {
        Text("Add")
    }
}

и ваша строка будет выглядеть следующим образом:

struct Row: View {

    @State var name: String

    var body: some View {
        HStack {
            Text(name)
            Spacer()
        }
        .padding()
        .transition(.move(edge: .leading))
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...