Chiều cao SwiftUI ScrollView VStack GeometryReader bị bỏ qua
Tôi muốn sử dụng ScrollView bên ngoài VStack, để nội dung của tôi có thể cuộn được nếu VStack mở rộng ra ngoài kích thước màn hình. Bây giờ tôi muốn sử dụng GeometryReaderbên trong VStack và nó gây ra vấn đề mà tôi chỉ có thể giải quyết bằng cách đặt khung GeometryReader, điều này không thực sự giúp ích cho tôi vì tôi sử dụng trình đọc để xác định kích thước chế độ xem.
Đây là mã không có ScrollView và nó hoạt động tốt:
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)
}
}
Điều này dẫn đến hình ảnh sau:
Nhãn có kích thước tùy chỉnh phải có chiều rộng đầy đủ, nhưng chiều rộng bằng một nửa chiều cao. Bây giờ nếu tôi bọc cùng một mã trong ScrollView, điều này sẽ xảy ra:
Không chỉ mọi thứ trở nên nhỏ hơn, mà bằng cách nào đó, chiều cao của Nhãn có kích thước tùy chỉnh cũng bị bỏ qua. Nếu tôi đặt chiều cao của GeometryReader, tôi có thể điều chỉnh hành vi đó, nhưng tôi muốn GeometryReader phát triển lớn như nội dung của nó. Làm thế nào tôi có thể đạt được điều này?
Cảm ơn
Trả lời
Cần phải hiểu rằng đó GeometryReaderkhông phải là một công cụ ma thuật, nó chỉ đọc không gian có sẵn trong ngữ cảnh hiện tại gốc, nhưng ... ScrollViewkhông có không gian khả dụng riêng, nó là 0, bởi vì nó xác định không gian cần thiết từ nội dung ... vì vậy sử dụng GeometryReaderở đây bạn đã có chu kỳ - con yêu cầu cha mẹ cho kích thước, nhưng cha mẹ mong đợi kích thước từ con ... Trình kết xuất SwiftUI bằng cách nào đó giải quyết điều này (tìm kích thước tối thiểu đã biết), chỉ để không bị lỗi.
Đây là giải pháp khả thi cho kịch bản của bạn - công cụ thích hợp ở đây là tùy chọn chế độ xem. Được chuẩn bị và thử nghiệm với 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()
}
}
Lưu ý: ... và không sử dụng GeometryReader nếu bạn không chắc chắn về ngữ cảnh mà chế độ xem của bạn.