Peter
Peter

Reputation: 922

SwiftUI – Multi column TableView in macOS

I have been experimenting a bit with SwiftUI and can’t seem to find any information at all about how to use SwiftUI to create a multi column TableView as in NSTableView. All the examples I have managed to find show a single column of data.

The documentation at Apple even specifies that the SwiftUI List structure is for single column display of rows of data. This is a pretty fundamental data structure for apps on MacOS yet there seems to be zero mention of it anywhere!

Can someone shed some light on this? I presume it just isn’t ready yet but still.

Upvotes: 37

Views: 7197

Answers (5)

Andy Jazz
Andy Jazz

Reputation: 58563

SwiftUI Table in Xcode 14.0+

SwiftUI Table is a container that presents rows of data arranged in one or more columns, optionally providing the ability to select its members and sort its members in ascending or descending order. Each TableColumn struct displays a view for each row in a table.

enter image description here

Here's a code:

import SwiftUI

struct Item: Identifiable {
    var id: Int
    var item: String
    var qty: String
}

struct ContentView: View {
     
    @State var sorting = [KeyPathComparator(\Item.qty)]
    @State var selecting: Int?      
    @State var items: [Item] = [1,2,3,4,5].map {
        Item(id: $0, item: "item \($0)", qty: "qty " + String($0))
    }      
    var body: some View {            
        VStack {  
            Table(items, selection: $selecting, sortOrder: $sorting) {
                TableColumn("##", value: \.id) { entity in
                    Text("\(entity.id)").font(.title2)
                }
                TableColumn("What", value: \.item) { entity in
                    Text(entity.item).font(.title2)
                }
                TableColumn("Qty", value: \.qty) { entity in 
                    Text("\(entity.qty)").font(.title2)
                }
            }.frame(width: 900, height: 210)
             .onChange(of: sorting) { items.sort(using: $0) }
             .font(.title)
        }
    }
}

Upvotes: 6

AzeTech
AzeTech

Reputation: 707

For Example:-

struct StaffList: View {
   private var data = [Data]()
    var body: some View {
       List {
            HStack() {
                    VStack {
                        //Column 1 Data
                        Text("Name")
                            .foregroundColor(.primary)
                            .font(.headline)
                        Divider()
                        ForEach(data) { person in
                          //  Text(person.name) this is list ...
                        }
                    }
                Divider()
                VStack {
                    //Column 2 Data
                    Text("Creation Date")
                        .foregroundColor(.primary)
                        .font(.headline)
                    Divider()
                        ForEach(data) { person in
                          //  Text(person.name) this is list ...
                        }
                }
            }
        }
    }
}

Upvotes: -1

Pranav Kasetti
Pranav Kasetti

Reputation: 9935

Update for macOS 12+ (Monterey)

In macOS Monterey, NSTableView can now be wrapped with Table. In addition, Table can support TableColumns with key paths and trailing closures.

struct ContentView: View {
  @State private var characters = StoryCharacter.previewData

  var body: some View {
    Table(characters) {
      TableColumn("🛠") { CharacterIcon($0) }
        .width(20)
      TableColumn("Villain") { Text($0.isVillain ? "Villain" : "Hero") }
        .width(40)
      TableColumn("Name", value: \.name)
      TableColumn("Powers", value: \.powers)
    }
  }
}

Upvotes: 14

Curiosity
Curiosity

Reputation: 264

This is now available starting with macOS 12 through Table.

Upvotes: 3

Ben O
Ben O

Reputation: 238

You could create an HStack and then have a divider between two VStacks where you would put your different columns of data. It would look something like this:

List {
    HStack {
        VStack {
            //Column 1 Data
        }
    }
    Divider()
    VStack {
        //Column 2 Data
    }
}

And then just repeat this for however many columns of data are needed.

Upvotes: 2

Related Questions