What is the most optimal way to layout a View with different settings for portrait and landscape orientation in Swift?

241 Views Asked by At

I have a grid which fits its column width and row height depending on the available size and a stepper accessed through a settings view on a pop over sheet. In this particular example I have a 13 by 18 grid in portrait orientation and want to implement an 18 by 13 grid when in landscape orientation. Otherwise I get also a 13 by 18 grid with lots of empty space on the sides.

enter image description here

enter image description here

I thought of using a ViewBuilder and an if - else statement to create a Grid with items sorted with 13 columns and 18 rows or 18 columns and 13 rows depending on device orientation.

if UIDevice.current.orientation.isLandscape {
    GridThatFits(items: viewModel.locationsForHorizontalOrientation, columnsCount: viewModel.height, rowCount: viewModel.width) { location in
        ZStack {
            RoundedRectangle(cornerRadius: 5)
            imageFor(location)
        }
    }
} else {
    GridThatFits(items: viewModel.locations, columnsCount: viewModel.width, rowCount: viewModel.height) { location in
        ZStack {
            RoundedRectangle(cornerRadius: 5)
            imageFor(location)
        }
    }
}

struct GridThatFits<Item, ItemView>: View where ItemView: View, Item: Hashable {
    var items: [Item]
    var columnsCount: Int
    var rowCount: Int
    var content: (Item) -> ItemView
    
    var body: some View {
        GeometryReader { geometry in
            VStack {
                // 10 points padding between items
                let columnsWidth = min(
                    (geometry.size.width - 10 * CGFloat(columnsCount + 1)) / CGFloat(columnsCount),
                    (geometry.size.height - 10 * CGFloat(rowCount + 1)) / CGFloat(rowCount)
                )
                
                let columns: [GridItem] = Array(repeating: .init(.fixed(columnsWidth)), count: columnsCount)
                LazyVGrid(columns: columns) {
                    ForEach(items, id: \.self) { item in
                        content(item).frame(minWidth: columnsWidth, minHeight: columnsWidth)
                    }
                }
            }
        }
    }
}

This approach seems to cause some bug somewhere else in my code and the correct arrangement gets updated only after tapping on a square. Is there another way to implement these different grid arrangements depending on device orientation?

0

There are 0 best solutions below