Swift UI - How to make Image Grids?

Viewed 7846

Need to create a grid of images with SwiftUI, that dynamically change rows according to screen width.

When I use List, I can only get one column..

I tried Hstacks to make 2 columns, but then it doesn't work dynamically for screen width.

Ex: iPhone portrait should have 1 column Ex: iPhone landscape should have 2 column

import SwiftUI

struct ProductGrid : View {
    var body: some View {

        List(0 ..< 5) { item in

            VStack() {
                Image("product")
                HStack {

                   ProfileImageSmall()
                        VStack {
                            Text("Product")

                            Text("Username")


                        }


                    }



            }

        }
    }
}

How can I make a grid that column count adapts to screen width?

2 Answers

Available for XCode 12

import SwiftUI

//MARK: - Adaptive
struct ContentView: View {
    
    var body: some View {
        ScrollView {
            LazyVGrid(columns: [GridItem(.adaptive(minimum:100))]) {
                ForEach(yourObjects) { object in
                    YourObjectView(item: object)
                }
            }
        }
    }
}

//MARK: - Custom Columns
struct ContentView: View {
        
    var body: some View {
         ScrollView {   
             LazyVGrid(columns: Array(repeating: GridItem(), count: 4)) {
                 ForEach(yourObjects) { object in
                     YourObjectView(item: object)
                 }
             }
         }
    }
}

Don't forget replace the info objects with your info and YourObjectView with your customView.

You can use size classes to determine the right interface orientation.

enter image description here

To check whether an iPhone is landscape or not, you can check the vertical size class environment value.

When the device is portrait, it is set to .regular, otherwise it returns .compact.

You can use @Environment property wrapper to subscribe to that environment value, and have the view redraw itself when a change occur.

In this example, I have a large green square displayed when the iPhone is in portrait mode, and two smaller squares (one green, one pink) when the iPhone is in landscape mode.

struct ContentView: View {

    @Environment(\.verticalSizeClass) var verticalSizeClass: UserInterfaceSizeClass?

    var body: some View {
        GeometryReader { geometry in
            ScrollView {
                ForEach(1...24) { item in
                    if self.verticalSizeClass == .regular {
                        HStack {
                            Spacer(minLength: geometry.size.width * 0.15)
                            Rectangle()
                                .foregroundColor(.green)
                                .frame(width: geometry.size.width * 0.70,
                                       height: geometry.size.height * 0.3)
                            Spacer(minLength: geometry.size.width * 0.15)
                        }
                    } else {
                        HStack {
                            Spacer(minLength: geometry.size.width * 0.05)
                            Rectangle()
                                .foregroundColor(.green)
                                .frame(width: geometry.size.width * 0.40,
                                       height: geometry.size.height)
                            Spacer(minLength: geometry.size.width * 0.05)
                            Rectangle()
                                .foregroundColor(.pink)
                                .frame(width: geometry.size.width * 0.40,
                                       height: geometry.size.height)
                            Spacer(minLength: geometry.size.width * 0.05)
                        }
                    }
                }
            }
        }
    }

}

Portrait layout:

enter image description here

Landscape layout:

enter image description here

Related