我想像 safari 一样通过滚动方向显示或隐藏项目。向上滚动时隐藏某些内容,向下滚动时显示它。
我认为,simultaneousGesture是一个更好的解决方案,因为它不会阻止scrollView事件。
ScrollView {
}
.simultaneousGesture(
DragGesture().onChanged({
let isScrollDown = 0 < $0.translation.height
print(isScrollDown)
}))
此方法仅在屏幕停止滚动时检测新的滚动
您可以使用 DragGesture 值
ScrollView {
...
}
.gesture(
DragGesture().onChanged { value in
if value.translation.height > 0 {
print("Scroll down")
} else {
print("Scroll up")
}
}
)
您可以使用 GeometryReader 获取 ScrollView 中视图中的一个的全局位置来检测滚动方向。下面的代码将打印出当前的 midY 位置。根据 +/- 值,您可以显示或隐藏其他视图。
struct ContentView: View {
var body: some View {
ScrollView{
GeometryReader { geometry in
Text("Top View \(geometry.frame(in: .global).midY)")
.frame(width: geometry.size.width, height: 50)
.background(Color.orange)
}
}.frame(minWidth: 0, idealWidth: 0, maxWidth: .infinity, minHeight: 0, idealHeight: 0, maxHeight: .infinity, alignment: .center)
}
}
当前的答案都不适合我,所以我使用了
PreferenceKey
更改。
经测试可在 Xcode 14.3.1 和 iOS 16.6 中工作。
@State var previousViewOffset: CGFloat = 0
let minimumOffset: CGFloat = 16 // Optional
...
ScrollView {
VStack {
...
}.background(GeometryReader {
Color.clear.preference(key: ViewOffsetKey.self, value: -$0.frame(in: .named("scroll")).origin.y)
}).onPreferenceChange(ViewOffsetKey.self) {
let offsetDifference: CGFloat = abs(self.previousViewOffset - $0)
if self.previousViewOffset > $0 {
print("Is scrolling up toward top.")
} else {
print("Is scrolling down toward bottom.")
}
if offsetDifference > minimumOffset { // This condition is optional but the scroll direction is often too sensitive without a minimum offset.
self.previousViewOffset = $0
}
}
}.coordinateSpace(name: "scroll")
...
struct ViewOffsetKey: PreferenceKey {
typealias Value = CGFloat
static var defaultValue = CGFloat.zero
static func reduce(value: inout Value, nextValue: () -> Value) {
value += nextValue()
}
}
总结一下:
background
修饰符及其内容。onPreferenceChange
修饰符和内容。coordinateSpace
修饰符。coordinateSpace
名称与 named
偏好框架相匹配。ViewOffsetKey
首选项键。您可以像这样使用predictedEndLocation和位置
/// A prediction, based on the current drag velocity, of where the final
/// location will be if dragging stopped now.
public var predictedEndLocation: CGPoint { get }
DragGesture()
.onChanged({ gesture in
if (gesture.location.y > gesture.predictedEndLocation.y){
print("up")
} else {
print("down")
}
})
我认为@Mykels 的答案是最好的,并且在 IOS16 中运行良好。不过,它的一项改进是仅在滚动量大于最小偏移量时才调用所需的函数,否则如果滚动量小于最小偏移量,最终可能会调用错误的函数。这是我的更新版本:
ScrollView(.vertical){
LazyVStack {
...
}.background(GeometryReader {
Color.clear.preference(key: ViewOffsetKey.self, value: -$0.frame(in: .named("scroll")).origin.y)
}).onPreferenceChange(ViewOffsetKey.self) { currentOffset in
let offsetDifference: CGFloat = self.previousScrollOffset - currentOffset
if ( abs(offsetDifference) > minimumOffset) {
if offsetDifference > 0 {
print("Is scrolling up toward top.")
} else {
print("Is scrolling down toward bottom.")
}
self.previousScrollOffset = currentOffset
}
}
}
struct ViewOffsetKey: PreferenceKey {
typealias Value = CGFloat
static var defaultValue = CGFloat.zero
static func reduce(value: inout Value, nextValue: () -> Value) {
value += nextValue()
}