Home > Blockchain >  HTML-like table layout in SwiftUI View? LazyVGrid can’t do that
HTML-like table layout in SwiftUI View? LazyVGrid can’t do that

Time:05-02

I’d like to render a table of text cells in my SwiftUI View in a way, that every cell auto-resizes just so much that the text fits in it. So I did this:

    import SwiftUI

    struct ContentView: View {

        let words = "Die Würde des Menschen ist unantastbar. Sie zu achten und zu schützen ist Verpflichtung aller staatlichen Gewalt.".split(separator: " ")

        let columns = [
            GridItem(.flexible()),
            GridItem(.flexible()),
            GridItem(.flexible()),
            GridItem(.flexible()),
            GridItem(.flexible()),
        ]

       var body: some View {
           HStack{
               Spacer()
               LazyVGrid(columns: columns, spacing: 10) {
                   ForEach(words.indices, id: \.self) { idx in
                       HStack{
                           Text(words[idx])
                           Spacer()
                       }
                   }
               }
               Spacer()
           }.padding().frame(width:600)
       }
    }

However, the columns render with a fixed width and a lot of whitespace. (I don’t understand "flexible" in this context.) I‘d like to see HTML-table-like behavior.

How can I do this? I also thought about rendering the text offstage, calculating the width for every word and set the cell sizes "by hand". I know that NSString can tell me the size of the rendered string, but I don’t think SwiftUI can do that.

Any ideas? Bridge to aKWebView?

CodePudding user response:

GridItem(.flexible()) gives all cells a flexible, but SAME width. Seems like you are looking for flexible widths. The easiest way would be to skip LazyVGrid and just use HStack and VStack, they size themselves variable based on their content:

    var body: some View {
        
        HStack {
            ForEach(0..<5) { col in
                VStack(alignment: .leading) {
                    ForEach(0..<4) { row in
                        let index = row*5   col
                        if index < words.count {
                            Text(words[index])
                        } else {
                            Text("")
                        }
                    }
                }
            }
        }
        .padding()
        .frame(width:600)
    }

enter image description here

  • Related