SwiftUI ScrollView VStack GeometryReader 높이 무시
VStack 외부에서 ScrollView를 사용하여 VStack이 화면 크기 이상으로 확장되는 경우 내 콘텐츠를 스크롤 할 수 있습니다. 이제 GeometryReaderVStack 내에서 사용하고 싶습니다. 문제가 발생합니다. 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여기에 당신은 사이클이 있습니다-자식은 부모에게 크기를 요청하지만 부모는 자식의 크기를 기대합니다 ... SwiftUI 렌더러는 어떻게 든이 문제를 해결합니다 (알려진 최소 크기 찾기).
다음은 시나리오에 대한 가능한 솔루션입니다. 여기에서 적절한 도구는보기 기본 설정입니다. 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를 사용하지 마십시오.