5

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?

Matteo Pacini
  • 21,796
  • 7
  • 67
  • 74
Mane Manero
  • 3,086
  • 5
  • 25
  • 47
  • For now, you can't. That is, unless you use `UIKit` - which I honestly do not know if it's possible there. –  Jun 14 '19 at 18:43
  • Could you post a sketch of what are you trying to achieve? – Matteo Pacini Jun 14 '19 at 19:50
  • 2
    @dfd if what he's after is something like what the Photos app does, obviously it is possible. – matt Jun 14 '19 at 19:55
  • Does Photos use SwiftUI? A solution of “wrap a UIKit view in a `UIViewRepresentable`” might be the only answer right now, but it's not exactly a *good* answer. – rob mayoff Jun 14 '19 at 20:10
  • Which is why I posted a pretty vague comment. Using `HStack` and `VStack`, even a `List` won't do it. And again, as @matt indicates, what are the limitations in iOS 13 Photos? Does it use SwiftUI? UIKit? Best guess on my part is that **if** the new Photos app (really haven't played with it yet in iOS 13) handles what is needed **and** is not part of iOS 12, then it likely uses SwiftUI. BUT... is this something available in SwiftUI beta 1? I'm pretty sure there's many "not ready for prime time, less beta" features Apple is using. –  Jun 14 '19 at 20:48
  • @robmayoff Oh, no, I don't think it does. dfd said he didn't know if was possible _in UIKit_. I'm saying that it obviously is, since Photos has been making an adaptable grid for years. Assuming, of course, that that's what the OP is describing... – matt Jun 14 '19 at 20:53

2 Answers2

5

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.

gandhi Mena
  • 2,115
  • 1
  • 19
  • 20
3

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

Matteo Pacini
  • 21,796
  • 7
  • 67
  • 74
  • 1
    "The environment horizontalSizeClass changes when the interface rotates" Not on an iPad. – matt Jun 14 '19 at 23:12
  • Thanks again Matteo! But unfortunately as @matt mentioned this won't work for iPad. There should be some kind of "grid system" in SwiftUI that handles this kind of situation? – Mane Manero Jun 17 '19 at 09:29
  • Another thread about this: https://stackoverflow.com/questions/56466306/uicollectionview-and-swiftui – Mane Manero Jun 17 '19 at 09:33
  • @AlexandreLordelo you could provide a bespoke layout for iPad if `horizontalSizeClass == .regular && verticalSizeClass == .regular`? – Matteo Pacini Jun 17 '19 at 10:11