如何解决onReceiveself.timer在NavigationView内部不起作用
我在Scrollview
的此页面上有一个自定义标头,仅在它滚动到一定高度时才显示。我将GeometryReader
与onReceive
结合使用来不断检查当前滚动高度:
@State var userInfoUpateInterval = Timer.publish(every: 0.1,on: .current,in: .tracking).autoconnect()
@State var showHeader: Bool = false
var body: some View {
NavigationView {
ZStack(alignment: .top) {
ScrollView(.vertical) {
GeometryReader { geometry in
Text("User info component").onReceive(self.userInfoUpateInterval) { (_) in
self.onUserInfoLayoutChange(geometry)
}
}
VStack {
Text("content")
}.frame(width: UIScreen.screenWidth,height: 1500)
}
ProfileHeader(title: "user.userName",showHeader: $showHeader)
}
}
}
在我将ZStack
包裹在NavigationView
中之前,滚动和标题的隐藏/显示是完美的。 onReceive
不再被触发。如果我将NavigationView
与ZStack
交换,一切将再次按预期工作。
我已经看到了这个Timer onReceive not working inside NavigationView问题,但是我没有条件部分。这是SwiftUI错误还是我做错了?
解决方法
以下是针对您的案例的可能解决方案的演示。在Xcode 11.4 / iOS 13.4上进行了测试(并且向前兼容)
这个想法不是通过计时器而是通过视图首选项已读取/跟踪的视图位置变化来做出反应。
struct ViewOffsetKey: PreferenceKey {
typealias Value = CGFloat
static var defaultValue: CGFloat { 0 }
static func reduce(value: inout Value,nextValue: () -> Value) {
value = value + nextValue()
}
}
struct DemoView: View {
@State var showHeader: Bool = false
var body: some View {
NavigationView {
ZStack(alignment: .top) {
ScrollView(.vertical) {
Text("User info component")
.background(GeometryReader {
Color.clear.preference(key: ViewOffsetKey.self,value: -$0.frame(in: .named("scroll_area")).origin.y) })
VStack {
Text("content")
}.frame(maxWidth: .infinity,minHeight: 1500)
}.coordinateSpace(name: "scroll_area")
if showHeader {
Text("ProfileHeader")
}
}
}
.onPreferenceChange(ViewOffsetKey.self) {
self.showHeader = $0 > 200 // << your condition
}
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。