更改数据源时的 SwiftUI 列表动画

Kev*_*ers 3 swiftui

我的 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
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

现在,我不想在这里使用默认的列表动画。我希望列表项水平滑动。因此,当您按>箭头查看下一类别的项目时,屏幕上的现有项目应移至左侧,而新项目应从右侧进入。当您按下按钮时则相反<。基本上,它应该感觉像一个具有多个页面的集合视图,您可以在多个页面之间滚动。

previous我已经发现将和next函数的内容包装起来withAnimation会将默认列表动画更改为其他内容。然后,我尝试添加.transition(.slide)到列表(以及其中的文本)以更改新动画,但这没有效果。不知道如何更改列表的动画,尤其是两个不同按钮的不同的一个/方向。

使用带有每个类别列表的 ScrollView 不会在实际应用程序中扩展,尽管这可能是这个行数很少的简单示例的解决方案:)

Pau*_*ton 6

如果您的按钮按照您的建议进行包装,并且我添加了一个简单的方向布尔值:

Button(action: {
            withAnimation {
                slideRight = true
                self.previous()
            }
        }) {
          Text("<")
        }
Run Code Online (Sandbox Code Playgroud)

另一个方向则相反:

Button(action: {
            withAnimation {
                slideRight = false
                self.next()
            }
        }) {
          Text(">")
        }
Run Code Online (Sandbox Code Playgroud)

然后你可以像这样转换你的视图:

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

请注意,为了使列表不显示动画,我们需要每次为列表提供一个新的唯一 ID,请参阅本文: 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)
    }
}
Run Code Online (Sandbox Code Playgroud)

动画列表更改