I have a List made of cells, each containing an image, and a column of text, which I wish laid out in a specific way. Image on the left, taking up a quarter of the width. The rest of the space given to the text, which is left-aligned.
Here's the code I got:
struct TestCell: View {
let model: ModelStruct
var body: some View {
HStack {
Image("flag")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: UIScreen.main.bounds.size.width * 0.25)
VStack(alignment: .leading, spacing: 5) {
Text("Country: Moldova")
Text("Capital: Chișinău")
Text("Currency: Leu")
}
.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
}
}
}
struct TestCell_Previews: PreviewProvider {
static var previews: some View {
TestCell()
.previewLayout(.sizeThatFits)
.previewDevice("iPhone 11")
}
}
And here are 2 examples:
As you can see, the height of the whole cell varies based on the aspect ratio of the image.
$1M question - How can we make the cell height hug the text (like in the second image) and not vary, but rather shrink the image in a scaleAspectFit manner inside the allocated rectangle
Note!
PreferenceKey
s, as the cells will be part of a List, and there's some peculiar behaviour I'm trying to grasp around cell reusage, and onPreferenceChange
not being called when 2 consecutive cells have the same height. To exhibit all this combined behaviour, make sure your model varies between cells when you test it.The content-hugging priority represents the resistance a view has to grow larger than its intrinsic content size. Conversely, the compression-resistance priority represents the resistance a view has to shrink beyond its intrinsic content size.
horizontal content hugging priority: green(252)- blue(251) So, larger the content hugging priority , the views bound will hug to the intrinsic content more tightly preventing the view to grow beyond its intrinsic content size.
setContentHuggingPriority(_:for:)Sets the priority with which a view resists being made larger than its intrinsic size. iOS 6.0+ iPadOS 6.0+ Mac Catalyst 13.1+ tvOS 9.0+
Here is a possible solution, however it uses GeometryReader inside the background property of the VStack, to detect their height. That height is being applied to the Image then. I used SizePreferenceKey
from this solution.
struct SizePreferenceKey: PreferenceKey {
typealias Value = CGSize
static var defaultValue: Value = .zero
static func reduce(value _: inout Value, nextValue: () -> Value) {
_ = nextValue()
}
}
struct ContentView6: View {
@State var childSize: CGSize = .zero
var body: some View {
HStack {
Image("image1")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: UIScreen.main.bounds.size.width * 0.25, height: self.childSize.height)
VStack(alignment: .leading, spacing: 5) {
Text("Country: Moldova")
Text("Capital: Chișinău")
Text("Currency: Leu")
}
.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
.background(
GeometryReader { proxy in
Color.clear.preference(key: SizePreferenceKey.self, value: proxy.size)
}
)
}
.onPreferenceChange(SizePreferenceKey.self) { preferences in
self.childSize = preferences
}
.border(Color.yellow)
}
}
Will look like this.. you can apply different aspect ratios for the Image of course.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With