在 swiftui 中滚动时动画标题

Sor*_*ica 5 animation ios swiftui

我正在尝试构建一个视图,其中标题固定在视图顶部,并根据滚动偏移量更改其大小,当偏移量为 0 时,标题变大,当用户滚动时标题变小

struct ContentView : View {
    
    @State var largeHeader = true
    
    var body: some View {
        VStack {
            Text("HEADER").padding(.vertical, largeHeader ? 30 : 10)
            Divider()
            ScrollView {
                VStack {
                    Text("Content0")
                        .padding()
                    Text("Content1")
                        .padding()
                    Text("Content2")
                        .padding()
                }
                .background(GeometryReader { geometryProxy -> Color in
                    DispatchQueue.main.async {
                        largeHeader = geometryProxy.frame(in: .named("myspace")).minY >= 0
                    }
                    return Color.clear
                })
            }
            .coordinateSpace(name: "myspace")
        }.animation(.default)
    }
}
Run Code Online (Sandbox Code Playgroud)

当滚动内容较长时它工作正常,但是当内容很少时,如上面的代码所示,我会出现闪烁(在设备上情况更糟,但 gif 质量很低)

在此输入图像描述

知道如何修复它吗?

Mof*_*waw 8

看来有一些干扰正在发生。

我找到了两种解决方案,这取决于你想要的效果是什么。

解决方案1

想法:使用ZStackScrollView和你的标题不会干扰。

struct ContentView: View {
    
    @State var largeHeader = true
    
    var body: some View {
        ZStack {
            ScrollView {
                VStack {
                    ForEach(0..<3) { i in
                        Text("Content\(i)")
                            .padding()
                    }
                }
                .background(GeometryReader { geometryProxy -> Color in
                    DispatchQueue.main.async {
                        largeHeader = geometryProxy.frame(in: .named("1")).minY >= 0
                    }
                    return Color.clear
                })
            }
            .coordinateSpace(name: "1")
            .offset(y: largeHeader ? 100 : 60)
            
            VStack {
                VStack {
                    Spacer()
                    Text("HEADER")
                        .padding()
                    Divider()
                }
                .frame(maxWidth: .infinity)
                .frame(height: largeHeader ? 140 : 100)
                .background(Color.white)
                
                Spacer()
            }
            .edgesIgnoringSafeArea(.all)
        }
        .animation(.default)
    }
}
Run Code Online (Sandbox Code Playgroud)

无论内容高度有多大,这个标题总是会改变高度。

解决方案2

想法:只有当有足够的内容可以滚动时才更改标题高度。

解决方案:找出scrollview-content的高度。

struct ContentView: View {
    
    @State var largeHeader = true
    @State var scrollViewScrollable = false
    
    var body: some View {
        VStack {
            Text("HEADER").padding(.vertical, largeHeader ? 30 : 10)
            Divider()
            ScrollView {
                VStack {
                    ForEach(0..<3) { i in
                        Text("Content\(i)")
                            .padding()
                    }
                }
                .background(GeometryReader { geometryProxy -> Color in
                    if scrollViewScrollable {
                        DispatchQueue.main.async {
                            largeHeader = geometryProxy.frame(in: .named("1")).minY >= 0
                        }
                    }
                    return Color.clear
                })
                .background(
                    GeometryReader { proxy in
                        Color.clear.onAppear {
                            scrollViewScrollable = proxy.frame(in: .named("1")).size.height >= UIScreen.main.bounds.size.height - 100
                        }
                    }
                )
            }
            .coordinateSpace(name: "1")
        }
        .animation(.default)
    }
}
Run Code Online (Sandbox Code Playgroud)