In this code, is it a problem usage of geometryReader both in view and in cells? is there a different way to achieve same result?). to be clear if I have 5 cells, I had hard time keeping the image in the same position even if text is on single line. I need to avoid getting some cell with image close to top and other at a lower position
I'd like to keep these requirements:
the images should be at the same level in each cells, if the text is on a single line, I need the image is same "level" of cells where text is on two lines.
I'd like to avoid hard coded sizes, this way hopefully the views are more flexible
import SwiftUI struct TestForBackgroundImage: View { @EnvironmentObject var classFromEntryPoint: ClassFromEntryPoint private static let minCommonWidth: CGFloat = 100 let columns = [GridItem(.adaptive(minimum: minCommonWidth))] var body: some View { ScrollView { LazyVGrid(columns: columns, spacing: 10) { ForEach(0...100, id: \.self) { item in ItemView(item: item) .onTapGesture { print(item) } } } .padding() } .backgroundImage2() } private struct ItemView: View { let item: Int var body: some View { GeometryReader { geometry in VStack(alignment: .center) { Image(systemName: "apple.logo") // Image(AppConstants.FixedImages.backgroundImage.rawValue) .resizable() .scaledToFill() .foregroundStyle(.secondary) .frame(width: geometry.size.width * 0.4, height: geometry.size.width * 0.4) //this one is here for testing multiple text lenghts to be certain the image is always at the same level in each cell if item % 2 == 0 { Text("short: \(item)") .frame(height: geometry.size.width * 0.25) .lineLimit(2) .minimumScaleFactor(0.8) .multilineTextAlignment(.center) .padding(.horizontal, 5) .padding(.top, 5) } else { Text("middle lenght text: \(item)") .frame(height: geometry.size.width * 0.25) .lineLimit(2) .minimumScaleFactor(0.8) .multilineTextAlignment(.center) .padding(.horizontal, 5) .padding(.top, 5) } } .frame(width: geometry.size.width, height: geometry.size.width) .background(.teal) .shadow(color: .black.opacity(0.3), radius: 10, x: 0, y: 10) } .aspectRatio(1, contentMode: .fit) } } } struct BackgroundImage2: ViewModifier { func body(content: Content) -> some View { GeometryReader { geometry in content .background( Image(AppConstants.FixedImages.backgroundImage.rawValue) .resizable() .scaledToFill() .opacity(0.4) .offset(x: -geometry.size.width / 2, y: geometry.size.height / 2) ) } } } extension View { func backgroundImage2() -> some View { modifier(BackgroundImage2()) } }
If you don't need the 1:1 aspect ratio, you can just
scaleToFitthe image, and add aSpacerbetween the text and the image (or after the text, depending on what alignment you want):The spacer pushes the image and text apart from each other, making sure that the images always align at the top.
If you are not satisfied with this, then I suggest keeping the
GeometryReader. Making theText1/4 of the height of theVStackis very reasonable.Otherwise, you can put an invisible 2-line text, and overlay the actual text on top of it. IMO, this is more of a hack when compared to
GeometryReader.