Home > Software design >  Formatting Custom Grid View to Periodic Table in Swift?
Formatting Custom Grid View to Periodic Table in Swift?

Time:11-09

How can I reformat the code of GridStack in the view body so I may duplicate it per row, such as 1 row of 2 columns, 2 rows of 8 columns, 4 rows of 18 columns, 2 rows of 15 columns?, I am cutting out the holes with this Hypothesis to shape an Interactive Periodic Table, refer to image attached.

@jnpdx has provided an example for display function per cell coordinate, along with this i will need an ontapgesture to operate the overlay of data per cell so I may send information to other menu fields.

@jnpdx so now right before the roundedrectangle in this edit and turn on the display function commented out, i need to some how over lay the custom data per cell instead of hydrogen on every cell plus create an ontapgesture to send globally to other menu fields in the application?

func readiness

struct GridStack<Content: View>: View {
   
    let rows: Int
    let columns: Int
    let content: (Int, Int) -> Content
    
    

    //func shouldDisplayAtCoord(row: Int, column: Int) { if row == 0 && column > 1 { return true } }
    
    var body: some View {
        VStack {
                    ForEach(0 ..< rows, id: \.self) { row in
                       
                        HStack {
                            ForEach(0 ..< columns, id: \.self) { column in
                                ZStack{
                                RoundedRectangle(cornerRadius: 5)
                                            .fill(Color.brown)
                                            .frame(width: 40, height: 50)
                            Image("RadicalDeepscale30").opacity(0.4)
                            content(row, column)
                              
                                 
                            }
                            }
                        }
                    }
                }
       
    }
    init(rows: Int, columns: Int, @ViewBuilder content: @escaping (Int, Int) -> Content) {
        self.rows = rows
        self.columns = columns
        self.content = content
    }
}

// An example view putting GridStack into practice.
struct DETEView: View {
    var body: some View {
        
        VStack(alignment: .center) {
            Text("DART Edge Table of Elements")
                .font(.largeTitle)
                .bold()
                //.colorInvert()
                .padding(.top, 20)
                .shadow(radius: 3)
        }
        
            VStack(alignment: .center) {
                HStack(alignment: .center){
                    VStack(alignment: .center) {
        GridStack(rows: 9, columns: 18) { row, col in
            VStack(alignment: .leading){
                HStack(alignment: .top) {
            VStack(alignment: .leading) {
            Text("1")
                .font(.system(size: 9))
               // .bold()
                //.shadow(radius: 1)
            }
                }
                HStack(alignment: .center) {
                VStack(alignment: .center){
                    Text("H")
                        .font(.system(size: 12))
                        .bold()
                        //.shadow(radius: 1)
            Text("Hydrogen")
                .font(.system(size: 7))
                //.bold()
               // .shadow(radius: 1)
                //.padding(.top, 1)
                }
                }
            }
        }
                    }
                }

            }.frame(width: 950, height: 670, alignment: .top).padding(.top, 20)
    }
        }

      

CodePudding user response:

This is a simple implementation using a similar strategy to what we discussed in the comments/chat. In this case, instead of using a function to determine whether the element should be displayed, it just looks it up in a table that lists the elements and stores them based on their coordinates on the grid.

struct GridStack<Content: View>: View {
    
    let rows: Int
    let columns: Int
    let content: (Int, Int) -> Content
    
    var body: some View {
        VStack {
            ForEach(0 ..< rows, id: \.self) { row in
                HStack {
                    ForEach(0 ..< columns, id: \.self) { column in
                        content(row,column)
                    }
                }
            }
        }
    }
}

struct ElementCoordinate: Hashable {
    var row : Int
    var column: Int
}

struct Element {
    var atomicNumber: Int
    var name : String
}

let tableOfElements : [ElementCoordinate:Element] = [
    ElementCoordinate(row: 1, column: 1):Element(atomicNumber: 1, name: "Hydrogen"),
    ElementCoordinate(row: 1, column: 18):Element(atomicNumber: 2, name: "Helium"),
    ElementCoordinate(row: 2, column: 1):Element(atomicNumber: 3, name: "Lithium"),
    ElementCoordinate(row: 2, column: 2):Element(atomicNumber: 4, name: "Beryllium"),
    ElementCoordinate(row: 2, column: 13):Element(atomicNumber: 5, name: "Boron"),
    ElementCoordinate(row: 2, column: 14):Element(atomicNumber: 6, name: "Carbon"),
]

struct ContentView: View {
    var body: some View {
        GridStack(rows: 9, columns: 18) { row, column in
            ZStack{
                if let element = tableOfElements[ElementCoordinate(row: row   1, column: column   1)] {
                    RoundedRectangle(cornerRadius: 5)
                        .fill(Color.brown)
                    Image("RadicalDeepscale30").opacity(0.4)
                    Text(element.name)
                }
            }
            .frame(width: 40, height: 50)
        }
    }
}

Note the 1 on the row and column numbers when querying the grid, since row and column are zero-based in the Swift code, but my tableOfElements starts with an index of 1.

This should show you not only how to do the layout, but how to associate each coordinate with a specific element.

Obviously the implementation details may change to fit your own model, but this should give you an idea of how to get started.

enter image description here

  • Related