更改 TabView 数据时无法阻止动画(SwiftUI)

问题描述 投票:0回答:1

我的

TabView
正在由一系列
Identifiable
项目填充。如果数组大小以将当前可见项目保留在屏幕上的方式增大或缩小,则视图会给我带来尴尬的闪烁动画。看起来像是从一个视图转换到另一个视图,即使视图、id 和演示文稿是相同的

有人知道如何停止动画吗?

我尝试过以下各种组合:

  1. .id()
    TabView
    和内容视图
     上显式设置 
    ForEach
  2. 设置
    .transition(.identity)
  3. 设置
    .animation(nil)

但一切都无济于事

struct Item: Identifiable, Equatable {
    let id: Int
    let color: Color
}

struct ContentView: View {

    @Namespace var animation
    @State var items: [Item] = []

    var body: some View {
        VStack {
            TabView {
                ForEach(items, id:\.id) { item in
                    item.color
                }
            }
            .background(Color.red)
            .tabViewStyle(.page)
            .frame(width: 300, height: 300)

            HStack {
                Button("State 1") {
                    self.items = [
                        .init(id: 0, color: .green),
                        .init(id: 1, color: .blue)
                    ]
                }

                Button("State 2") {
                    self.items = [
                        .init(id: 0, color: .green),
                            .init(id: 1, color: .blue),
                            .init(id: 2, color: .purple)
                    ]
                }
            }
        }
        .padding()
    }
}

animation swiftui identity
1个回答
0
投票

所以,我很高兴告诉您我能够通过一些技巧解决您的闪烁问题。首先,我使用 ZStack 嵌入 TabView 并在其顶部放置您在 TabView 中渲染的最后一种颜色的项目,其不透明度可以是 0 或 1,具体取决于状态是否正在更改。 我使用 TabView 的选择属性跟踪最后一种颜色。 这是代码:

@Namespace var animation
@State private var currentItem: Color = .green
@State private var isAboutToChange = false
@State var items: [Item] = []

var body: some View {
    VStack {
        ZStack {
            TabView(selection: $currentItem) {
                ForEach(items, id:\.id) { item in
                    item.color
                        .tag(item.color)
                }
            }
            .background(Color.red)
            .tabViewStyle(.page)
            
            currentItem
                .opacity(isAboutToChange ? 1 : 0)
                .overlay(alignment: .bottom) {
                    RenderColorsTabView()
                }
        }
        .frame(width: 300, height: 300)

        HStack {
            Button("State 1") {
                isAboutToChange = true
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {
                    self.items = [
                        .init(id: 0, color: .green),
                        .init(id: 1, color: .blue)
                    ]
                }
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
                    isAboutToChange = false
                }
            }

            Button("State 2") {
                isAboutToChange = true
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {
                    self.items = [
                        .init(id: 0, color: .green),
                        .init(id: 1, color: .blue),
                        .init(id: 2, color: .purple)
                    ]
                }
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
                    isAboutToChange = false
                }
            }
        }
    }
    .padding()
}


@ViewBuilder
func RenderColorsTabView() -> some View{
    TabView(selection: $currentItem) {
        ForEach(items, id:\.id) { item in
            item.color
                .tag(item.color)
        }
    }
    .tabViewStyle(.page)
}

你怎么看我需要一个布尔标志来注意到变化何时即将发生,这样我就可以将虚拟颜色的不透明度切换到 1 几分之一秒,这样闪烁就被隐藏了。另一个技巧是重用 TabView,通过在其底部显示点来使虚拟项目视图看起来真实。 我希望对您有所帮助!如果您有任何疑问,请告诉我。

© www.soinside.com 2019 - 2024. All rights reserved.