onReceive (self.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 ไม่ทำงานในคำถาม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
}
}
}