Reputation: 169
I want to achieve this (For the screenshots I used constant heights, just to visualize what I am looking for):
The two Views
containing text should together have the same height as the (blue) Image
View. The right and left side should also be of the same width. The important part: The Image
View can have different aspect ratios, so I can't set a fixed height for the parent View. I tried to use a GeometryReader
, but without success, because when I use geometry.size.height
as height, it takes up the whole screen height.
This is my code:
import SwiftUI
struct TestScreen: View {
var body: some View {
VStack {
GeometryReader { geometry in
HStack {
Image("blue-test-image")
.resizable()
.scaledToFit()
.frame(maxWidth: .infinity)
VStack {
Text("Some Text")
.padding()
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color.gray)
Text("Other Text")
.padding()
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color.gray)
}
.frame(maxWidth: .infinity, maxHeight: geometry.size.height /* should instead be the height of the Image View */)
}
}
Spacer()
}
.padding()
}
}
This is a screenshot of what my code leads to:
Any help would be appreciated, thanks!
Upvotes: 0
Views: 3834
Reputation: 391
To go further on @Steffen answer I moved the logic into a view extension.
extension View {
func getHeightOfView( completion: @escaping (_ height: Double) -> Void) -> some View {
self.background {
GeometryReader {
Color.clear.preference(
key: ViewHeightKeyTestScreen.self,
value: $0.frame(in: .local).size.height
)
}
}.onPreferenceChange(ViewHeightKeyTestScreen.self) {
completion($0)
}
}}
Now you can just add ".getHeightOfView" to a view you are trying to get the height of.
struct TestView: View {
@State var heightOfElement: CGFloat = CGFloat.zero
var body: some View {
HStack{
Text("short text this view will be the height of the other view")
.padding(10)
.frame(height: heightOfElement)
.frame(maxWidth: .infinity)
.background(Color.red)
Text("long long long text, this text is where we get height of other view, this is the tallest height element in hstack")
.padding(10)
.frame(maxWidth: .infinity)
.background(Color.red)
.getHeightOfView { height in
self.heightOfElement = height
}
}
}}
Upvotes: 0
Reputation: 169
This is how I solved it in this case:
import SwiftUI
struct TestScreen: View {
@State private var imageHeight = CGFloat.zero
var body: some View {
VStack {
HStack {
Image("blue-test-image")
.resizable()
.scaledToFit()
.frame(maxWidth: .infinity)
.background(GeometryReader {
Color.clear.preference(
key: ViewHeightKeyTestScreen.self,
value: $0.frame(in: .local).size.height
)
})
VStack {
Text("Some Text")
.padding()
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color.gray)
Text("Other Text")
.padding()
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color.gray)
}
.frame(maxWidth: .infinity, minHeight: self.imageHeight, maxHeight: self.imageHeight)
}
.onPreferenceChange(ViewHeightKeyTestScreen.self) {
self.imageHeight = $0
}
Spacer()
}
.padding()
}
}
struct ViewHeightKeyTestScreen: PreferenceKey {
static var defaultValue: CGFloat { 0 }
static func reduce(value: inout Value, nextValue: () -> Value) {
value += nextValue()
}
}
struct TestScreen_Previews: PreviewProvider {
static var previews: some View {
TestScreen()
}
}
Upvotes: 3