Home > Software engineering >  How to make multiple images in a single row have same height an correct aspect ratio?
How to make multiple images in a single row have same height an correct aspect ratio?

Time:12-29

The following is the screenshots.

The left iPhone, where there are 3 images in a single row, are having same height and correct aspect ratio. It is implemented using UIKit.

The right iPhone, where there are 3 images in a single row, are having different height and correct aspect ratio. It is implemented using SwiftUI.

enter image description here

I want to use SwiftUI, to achieve

  1. All 3 images are having same height.
  2. All 3 images are having correct aspect ratio.

In UIKit, this is how I achieve so

Step 1: Use a horizontal stack view

let horizontalStackView = UIStackView()

horizontalStackView.axis = .horizontal
horizontalStackView.distribution = .fill
horizontalStackView.alignment = .fill
horizontalStackView.spacing = spacing

Step 2: Assign correct constraint to every UIImageView based on original image dimension

let imageView = UIImageView()
imageView.contentMode = .scaleAspectFit

let multiplier = CGFloat((Double)(attachment.height) / (Double)(attachment.width))
imageView.heightAnchor.constraint(
    equalTo: imageView.widthAnchor,
    multiplier: multiplier).isActive = true

However, I am not sure how I can implement similar idea in SwiftUI. So far, this is how I achieve imperfect outcome at the right iPhone screenshot. They are having correct aspect ratio. But they are not having same height.

SwiftUI, incorrect outcome

struct ContentView: View {
    var body: some View {
        HStack {
            VStack(alignment: .leading, spacing: 4) {
                HStack(spacing: 2) {
                    Image("0").resizable().aspectRatio(contentMode: .fit)
                    
                    Image("3").resizable().aspectRatio(contentMode: .fit)
                    
                    Image("2").resizable().aspectRatio(contentMode: .fit)
                }
                Text("Hello, world!")
                
                Spacer(minLength: 0)
            }
            
            Spacer(minLength: 0)
        }
    }
}

Do you have idea, how I can achieve the same outcome in SwiftUI, as I did in UIKit? Thanks.

CodePudding user response:

Call frame(minWidth:idealWidth:maxWidth:minHeight:idealHeight:maxHeight:alignment:) and specify maxHeight. This ways all images will have the same size.

CodePudding user response:

define aspect ratio same for all images, like this:

 HStack(spacing: 2) {
                        
                        Image("0").resizable().aspectRatio(CGSize(width: 3, height: 3), contentMode: .fit)
                        
                        Image("1").resizable().aspectRatio(CGSize(width: 3, height: 3),contentMode: .fit)
                        
                        Image("2").resizable().aspectRatio(CGSize(width: 3, height: 3),contentMode: .fit)
                    }

you will get the desired output

CodePudding user response:

This seems to match what you did on UIKit with similar results. That is, using .fill on the images, restricting the horizontal stack to a fixed size and then calculating the HStack's height based on the device's width multiplied by the aspect ratio of the desired HStack.

This is the original code with changes:

struct ContentView: View {
    var body: some View {
        HStack {
            VStack(alignment: .leading, spacing: 4) {
                HStack(spacing: 2) {
                    Image("0").resizable().aspectRatio(contentMode: .fill)
                    Image("3").resizable().aspectRatio(contentMode: .fill)
                    Image("2").resizable().aspectRatio(contentMode: .fill)
                }
                .fixedSize(horizontal: true, vertical: false)
                .frame(height: UIScreen.main.bounds.size.width * (2.1 / 7))
                
                Text("Hello, world!").padding(.leading)
                
                Spacer(minLength: 0)
            }
            
            Spacer(minLength: 0)
        }
    }
}

The result for an iphone and an ipad:

enter image description here enter image description here

The .aspectRatio doesn't appear to work on an HStack so I used frame() instead. The magic number is a guestimate using the image of your desired layout (height / width). To match the original image, .padding(.leading) was also added.

  • Related