SwiftUI-滚动中的“隐藏/折叠”部分

时间:2019-08-14 12:14:54

标签: animation scrollview swiftui

我一直在寻找一种方法来复制Airbnb和许多其他工具所做的滚动动画,其中视图的顶部折叠/隐藏在滚动上,并在用户再次开始向上滚动时立即重新出现。请注意,在滚动附加的图像时,“日期”和“访客”按钮如何透明显示。

AirBnB

下面我附上了一个简单的视图,我只是将其放在一起。我尝试过在滚动视图的内部和外部都包含要折叠的区域。我猜想它需要在scrollview之外,因为它将独立地动画到您在滚动区域内的位置。

import SwiftUI

struct HideScrollView: View {
var body: some View {
    ScrollView {
        HStack {
            Text("Hide Me")
            Spacer()
        }.padding(.horizontal) .frame(height: 60) .background(Color.red) .foregroundColor(Color.white)
        ForEach(0 ..< 20) { item in
            VStack {
                HStack {
                    Text("Content Items")
                    Spacer()
                }.padding(.horizontal) .frame(height: 40)
            }
        }
    }

}

}

1 个答案:

答案 0 :(得分:2)

由于没有像didScroll之类的scrollView委托,因此有两种方法可以实现所需的结果。

#1您应该实现DragGesture手势,这不是首选方式,因为不会同时调用手势。

.simultaneousGesture(DragGesture().onChanged({ transition in
    if transition.translation.height > 0{
        withAnimation{
            self.viewIsShown = true
        }
    } else {
        withAnimation{
            self.viewIsShown = false
        }
    }
})
)

#2首选方式:根据Martin's tutorial,您应将GeometryReader内的ScrollView作为第一个孩子,这使您有可能获得元素在{{1}中的确切位置},就像这样:

GeometryReader

添加符合PreferenceKey协议的偏好密钥:

ScrollView(.vertical, showsIndicators: false) {
    GeometryReader { geometry in
        Color.clear.preference(key: OffsetKey.self, value: geometry.frame(in:.global).minY).frame(height: 0)
   }
//Your scrollable content here
}
   

读取在首选项键中设置的值,将struct OffsetKey: PreferenceKey { static let defaultValue: CGFloat? = nil static func reduce(value: inout CGFloat?, nextValue: () -> CGFloat?) { value = value ?? nextValue() } } 添加到ScrollView或其任何父视图中。

.onPreferenceChange(OffsetKey.self)@State都应该有initialOffest包装器。

offset

检查.onPreferenceChange(OffsetKey.self) { if self.initialOffset == nil || self.initialOffset == 0 { self.initialOffset = $0 //setting initialOffest when view first appeared. } self.offset = $0 } initialOffset之间的差异将告诉您视图的滚动状态。如果offset高于initialOffset,则视图将向下滚动,并且您应隐藏所需的视图。

根据您所发布的代码,它应如下所示:

offset