Jas*_*ain 7 animation scrollview swiftui
我一直在寻找一种方法来复制 Airbnb 和许多其他公司所做的滚动动画,视图的顶部折叠/隐藏在滚动中,并在用户再次开始向上滚动时立即重新出现。请注意“日期”和“访客”按钮在附加图像中滚动时如何变透明。
下面我附上了一个我刚刚拼凑起来的简单视图。我试过包括我想在滚动视图内外折叠的区域。我猜它需要在滚动视图之外,因为它会独立于您在滚动区域内的位置进行动画处理。
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)
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
}
小智 7
由于没有像 didScroll 或 any 之类的 scrollView 委托,因此有两种方法可以实现所需的结果。
#1 你应该实现 DragGesture 手势,这不是首选方式,因为手势不会被同时调用。
.simultaneousGesture(DragGesture().onChanged({ transition in
if transition.translation.height > 0{
withAnimation{
self.viewIsShown = true
}
} else {
withAnimation{
self.viewIsShown = false
}
}
})
)
Run Code Online (Sandbox Code Playgroud)
#2 首选方式:根据Martin 的教程,您应该使用GeometryReader
insideScrollView
作为第一个孩子,这使您有可能获得元素 inside 的确切位置GeometryReader
,如下所示:
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
}
Run Code Online (Sandbox Code Playgroud)
添加符合 PreferenceKey 协议的首选项键:
struct OffsetKey: PreferenceKey {
static let defaultValue: CGFloat? = nil
static func reduce(value: inout CGFloat?, nextValue: () -> CGFloat?) {
value = value ?? nextValue()
}
}
Run Code Online (Sandbox Code Playgroud)
读取在首选项键中设置的值,这样做添加 .onPreferenceChange(OffsetKey.self)
到 ScrollView 或其父视图中。
你应该有@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
}
Run Code Online (Sandbox Code Playgroud)
检查initialOffset
和之间的差异offset
会告诉您视图的滚动状态。如果initialOffset
高于offset
则您的视图向下滚动,您应该隐藏您想要的视图。
根据您发布的有问题的代码,它应该如下所示:
struct HideScrollView: View {
@State var initialOffset: CGFloat?
@State var offset: CGFloat?
@State var viewIsShown: Bool = true
var body: some View {
VStack{
HStack {
Text("Hide Me")
Spacer()
}.padding(.horizontal) .frame(height: 60) .background(Color.red) .foregroundColor(Color.white).opacity(self.viewIsShown ? 1 : 0)
ScrollView {
GeometryReader { geometry in
Color.clear.preference(key: OffsetKey.self, value: geometry.frame(in: .global).minY)
.frame(height: 0)
}
ForEach(0 ..< 20) { item in
VStack {
HStack {
Text("Content Items")
Spacer()
}.padding(.horizontal) .frame(height: 40)
}
}
}
}.onPreferenceChange(OffsetKey.self) {
if self.initialOffset == nil || self.initialOffset == 0 {
self.initialOffset = $0
}
self.offset = $0
guard let initialOffset = self.initialOffset,
let offset = self.offset else {
return
}
if(initialOffset > offset){
self.viewIsShown = false
print("hide")
} else {
self.viewIsShown = true
print("show")
}
}
}
}
struct OffsetKey: PreferenceKey {
static let defaultValue: CGFloat? = nil
static func reduce(value: inout CGFloat?,
nextValue: () -> CGFloat?) {
value = value ?? nextValue()
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1752 次 |
最近记录: |