SwiftUI List анимация при смене источника данных - PullRequest
1 голос
/ 31 января 2020

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

Код для упрощенной воспроизводимой версии (см. Скриншот ниже):

import SwiftUI

struct ContentView: View {
  private let models = [
    ["a", "b", "c", "d", "e", "f"],
    ["g", "h"],
    ["i", "j", "k", "l"],
  ]

  @State private var selectedCategory = 1

  private var viewingModels: [String] {
    models[selectedCategory]
  }

  var body: some View {
    VStack(spacing: 0.0) {
      HStack {
        Button(action: previous) {
          Text("<")
        }

        Text("\(selectedCategory)")

        Button(action: next) {
          Text(">")
        }
      }

      List(viewingModels, id: \.self) { model in
        Text(model)
      }
    }
  }

  private func previous() {
    if selectedCategory > 0 {
      selectedCategory -= 1
    }
  }

  private func next() {
    if selectedCategory < (models.count - 1) {
      selectedCategory += 1
    }
  }
}

enter image description here

Теперь я не хочу использовать анимацию списка по умолчанию здесь. Я хочу, чтобы элементы списка скользили горизонтально. Поэтому, когда вы нажимаете стрелку > для просмотра следующей категории элементов, существующие элементы на экране должны перемещаться влево, а новые элементы должны появляться справа. И наоборот при нажатии кнопки <. По сути, это должно выглядеть как представление коллекции с несколькими страницами, между которыми вы прокручиваете.

Я уже обнаружил, что перенос содержимого функций previous и next с помощью withAnimation меняет анимацию списка по умолчанию на что-то остальное. Затем я попытался добавить .transition(.slide) в список (и в текст внутри него), чтобы изменить новую анимацию, но это не дает эффекта. Не уверен, как изменить анимацию списка, особенно с другим направлением / направлением для двух разных кнопок.

Использование ScrollView со списком для каждой категории не будет масштабироваться в реальном приложении, даже если да, это может быть решением для этого простого примера с очень небольшим количеством строк:)

1 Ответ

1 голос
/ 10 февраля 2020

Если ваша кнопка обернута, как вы предложили, и я добавил простое логическое направление:

Button(action: {
            withAnimation {
                slideRight = true
                self.previous()
            }
        }) {
          Text("<")
        }

И наоборот для другого направления:

Button(action: {
            withAnimation {
                slideRight = false
                self.next()
            }
        }) {
          Text(">")
        }

Затем вы можете перенести свое представление например:

List(viewingModels, id: \.self) { model in
            Text(model)
        }
        .id(UUID())
        .transition(.asymmetric(insertion: .move(edge: slideRight ? .leading : .trailing),
                                removal: .move(edge: slideRight ? .trailing : .leading)))

Обратите внимание, что для того, чтобы список не анимировался, нам нужно каждый раз присваивать списку новый уникальный идентификатор, см. эту статью: https://swiftui-lab.com/swiftui-id/

ОБНОВЛЕНИЕ:

Я хотел предоставить полный сокращенный код, который работает, а также убрал использование UUID (), основываясь на комментариях ниже.

import SwiftUI

struct ContentView: View {
    private let models = [
        ["a", "b", "c", "d", "e", "f"],
        ["g", "h"],
        ["i", "j", "k", "l"],
    ]

    @State private var selectedCategory = 0
    @State private var slideRight = true

    private var viewingModels: [String] {
        models[selectedCategory]
    }

    var body: some View {
        VStack(spacing: 0.0) {
            HStack {
                Button(action: {
                    withAnimation {
                        if(self.selectedCategory - 1 < 0) { self.selectedCategory = self.models.count - 1 }
                            else {  self.selectedCategory -= 1 }
                        self.slideRight = true
                    }
                }) {
                    Image(systemName: "arrow.left")
                }

                Text("\(selectedCategory + 1)")

                Button(action: {
                    withAnimation {

                        if(self.selectedCategory + 1 > self.models.count - 1) { self.selectedCategory = 0 }
                            else { self.selectedCategory += 1 }
                        self.slideRight = false
                    }
                }) {
                    Image(systemName: "arrow.right")
                }
            }.font(.title)

            List(viewingModels, id: \.self) { model in
                Text(model)
            }
            .id(selectedCategory)
            .transition(.asymmetric(insertion: .move(edge: slideRight ? .leading : .trailing),
                                    removal: .move(edge: slideRight ? .trailing : .leading)))
        }.padding(10)
    }
}

animated list change

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...