SwiftUI ScrollView VStack GeometryReader ถูกละเว้น
ฉันต้องการใช้ ScrollView นอก VStack เพื่อให้เนื้อหาของฉันสามารถเลื่อนได้หาก VStack ขยายเกินขนาดหน้าจอ ตอนนี้ฉันต้องการใช้GeometryReaderภายใน VStack และมันทำให้เกิดปัญหาซึ่งฉันสามารถแก้ไขได้โดยการตั้งค่าเฟรม GeometryReader ซึ่งไม่ได้ช่วยอะไรฉันเลยเพราะฉันใช้โปรแกรมอ่านเพื่อกำหนดขนาดมุมมอง
นี่คือรหัสที่ไม่มี ScrollView และใช้งานได้ดี:
struct MyExampleView: View {
var body: some View {
VStack {
Text("Top Label")
.background(Color.red)
GeometryReader { reader in
Text("Custom Sized Label")
.frame(width: reader.size.width, height: reader.size.width * 0.5)
.background(Color.green)
}
Text("Bottom Label")
.background(Color.blue)
}
.background(Color.yellow)
}
}
ผลลัพธ์ในภาพต่อไปนี้:
ป้ายกำกับขนาดที่กำหนดเองควรมีความกว้างเต็ม แต่กว้างครึ่งหนึ่งสำหรับความสูง ตอนนี้ถ้าฉันห่อรหัสเดียวกันใน ScrollView สิ่งนี้จะเกิดขึ้น:
ไม่เพียง แต่ทำให้ทุกอย่างเล็กลง แต่ความสูงของ Custom Sized Label จะถูกละเลยไป ถ้าฉันตั้งค่าความสูงของ GeometryReader ฉันสามารถปรับพฤติกรรมนั้นได้ แต่ฉันต้องการให้ GeometryReader มีขนาดใหญ่พอ ๆ กับเนื้อหา ฉันจะบรรลุเป้าหมายนี้ได้อย่างไร?
ขอบคุณ
คำตอบ
ควรเข้าใจว่าGeometryReaderไม่ใช่เครื่องมือวิเศษเพียงแค่อ่านพื้นที่ว่างในบริบทหลักปัจจุบัน แต่ ... ScrollViewไม่มีพื้นที่ว่างของตัวเองเป็นศูนย์เนื่องจากกำหนดพื้นที่ที่ต้องการจากเนื้อหาภายใน ... ดังนั้นการใช้GeometryReaderที่นี่ คุณมีวงจร - เด็กถามผู้ปกครองสำหรับขนาด แต่ผู้ปกครองคาดหวังขนาดจากเด็ก ...
นี่คือวิธีแก้ปัญหาที่เป็นไปได้สำหรับสถานการณ์ของคุณเครื่องมือที่เหมาะสมนี่คือการตั้งค่ามุมมอง จัดทำและทดสอบด้วย Xcode 12 / iOS 14
struct DemoLayout_Previews: PreviewProvider {
static var previews: some View {
Group {
MyExampleView()
ScrollView { MyExampleView() }
}
}
}
struct MyExampleView: View {
@State private var height = CGFloat.zero
var body: some View {
VStack {
Text("Top Label")
.background(Color.red)
Text("Custom Sized Label")
.frame(maxWidth: .infinity)
.background(GeometryReader {
// store half of current width (which is screen-wide)
// in preference
Color.clear
.preference(key: ViewHeightKey.self,
value: $0.frame(in: .local).size.width / 2.0) }) .onPreferenceChange(ViewHeightKey.self) { // read value from preference in state self.height = $0
}
.frame(height: height) // apply from stored state
.background(Color.green)
Text("Bottom Label")
.background(Color.blue)
}
.background(Color.yellow)
}
}
struct ViewHeightKey: PreferenceKey {
typealias Value = CGFloat
static var defaultValue = CGFloat.zero
static func reduce(value: inout Value, nextValue: () -> Value) {
value += nextValue()
}
}
หมายเหตุ: ... และอย่าใช้ GeometryReader หากคุณไม่แน่ใจเกี่ยวกับบริบทที่มุมมองของคุณอยู่