简体   繁体   English

在 swiftui 中滚动时为 header 设置动画

[英]Animate header when scroll in swiftui

I'm trying to build a view where the header is fixed at the top of the view and it changes it's size according to the scroll offset, when the offset is 0 the header is bigger and when the user scrolls the header becomes smaller我正在尝试构建一个视图,其中 header 固定在视图的顶部,它根据滚动偏移量改变它的大小,当偏移量为 0 时 header 更大,当用户滚动 Z099FB995346F346F319E44 时

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)
    }
}

It works fine when the scroll content is longer, but when there is a little content, as in the code above I get this flickering (It's even worse on the device, but the gif quality is low)当滚动内容较长时它工作正常,但是当有一点内容时,如上面的代码中我得到这个闪烁(在设备上更糟,但 gif 质量低)

在此处输入图像描述

Any idea how to fix it?知道如何解决吗?

Looks like there is some interference going on.似乎有一些干扰正在发生。

I have found two workaround-solutions, it depends on what your desired effect is.我找到了两种解决方法,这取决于您想要的效果。

Solution 1解决方案 1

Idea: Using ZStack so that ScrollView and your header don't interfere.想法:使用ZStack以便ScrollView和您的 header 不会干扰。

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)
    }
}

The header of this one would always change the height, no matter how large the content-height is.这个 header 总是会改变高度,不管内容高度有多大。

Solution 2解决方案 2

Idea: Only change header height when there is enough content to scroll.想法:只有当有足够的内容滚动时才改变 header 高度。

Solution: Finding out the height of the 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)
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM