Rotation in Array in SwiftUI Grid

Viewed 60

I have a simple code which displays the Array in Grid. Is it possible to show items as an ark shaped array based Upon available width and Item numbers.

import SwiftUI

struct ContentView: View {
    let columns = [
        GridItem(.flexible()),
        GridItem(.flexible()),
        GridItem(.flexible()),
        GridItem(.flexible()),
        GridItem(.flexible())
    ]    
    var body: some View {
        ScrollView {
            LazyVGrid(columns: columns, spacing: 15) {
                ForEach(0..<20) { number in
                    
                    Rectangle()
                        .foregroundColor(Color.red)
                        .frame(width: 50, height: 80)
                        .cornerRadius(10)
                        .shadow(color: .black, radius: 5, x: 2, y: 2)
                        .overlay(
                            Text("\(number)").foregroundColor(.white)
                        )
                }
            }.padding(.all, 10)
        }
    }
}

Result is like this

Results

I would like something like following image.

Desired

Thank you.

1 Answers

It is just a math to calculate needed value of transformation, in general rotation plus translation.

Here is a simplified raw demo (you can calculate angles and offsets more accurately or differently - it is not a goal for demo). Tested with Xcode 13.4 / iOS 15.5 (it does not depend on platform)

demo

Main part only (cause each item is transformed depending on position in column):

ForEach(0..<20) { number in
    ItemView(value: number)  // << separate for simplicity
}

and

struct ItemView: View {
    var value: Int

    let baseAngl = CGFloat.pi/30
    var body: some View {
        //Button(action: {}) {  // << uncomment for demo
        Rectangle()
            .foregroundColor(Color.red)
            .frame(width: 50, height: 80)
            .cornerRadius(10)
            .shadow(color: .black, radius: 3, x: 1, y: 1)
            .overlay(
                Text("\(value)").foregroundColor(.white)
            )
            .rotationEffect(.radians(CGFloat(value % 5 - 2) * baseAngl), anchor: .bottom)
            .offset(y: UIScreen.main.bounds.height * (1 - cos(CGFloat(value % 5 - 2) * baseAngl)))
        //}
    }
}

Test module on GitHub

Related