SwiftUI Table rowHeight on macOS
Asked Answered
T

1

6

Looking for some advice trying to use Table on macOS using SwiftUI. Table was introduced in macOS 12, and I'm trying my darnedest to not step down into AppKit or replicate any existing functionality - I can't seem to find a solution to a SwiftUI version of NSTableView's rowHeight property.

There is a .tableStyle modifier but only allows for customization of insets and alternating row styling. Modifying the frame in the row views doesn't take effect, at least not the ways I've tried.

First, am I missing something obvious (or not obvious) and there is a way to do this? The underlying AppKit view is a SwiftUITableView that seems to inherit to NSTableView. I can adjust the rowHieght in the debugger, but only effects the table view's background. Second any recommendations on the way to approach this - other than using NSTableView and wrapping in a NSViewRepresentable, or manipulating the established NSView hierarchy using some SwiftUI/AppKit trickery?

Some elided code demonstrating the use of Table

struct ContentTable: View {
    var items: [ContentItem]
    
    @State var selection = Set<ContentItem.ID>()
    
    var body: some View {
        Table(selection: $selection) {
            TableColumn("Name") {
                Text($0.name)
                    .frame(height: 80) // Only way found to set height information
            }.width(min: 200, ideal: 250)

            TableColumn("Description", value: \.description)
        } rows: {
            ForEach(items) {
                TableRow($0)
            }
        }
        .tableStyle(.inset(alternatesRowBackgrounds: true))
    }
}

Here's a side-by-side of SF Symbols (Left) and the SwiftUI Table I'm using. Both are using the inset/alternating row styles. Presentation wise I'd like to give the rows more space to breathe.

side-by-side comparison

Tilney answered 17/11, 2021 at 3:57 Comment(5)
Can you give a sample code of what you want trying to do ? and a picture of what you expect in result ?Sterling
@Sterling apologies for the late response, I added a screen shot. There's not much code to provide as I'm looking for a way to do this. Here's a heavily elided version of what I have.Tilney
Hi there, have you found a way to change the row hight?Countenance
@Countenance unfortunately I have not. I put this project on the back burner for now, but my intent was just to use AppKit here. It was something I was attempting to write in 100% SwiftUI.Tilney
@Countenance Give my answer a try. You can also add some limited styling depending on the content view types.Yesman
Y
2

The way I do this is by utilizing the padding modifier in the content of declared TableColumns.

The important part is the table will adjust the row by the lowest padding value across all columns.

I would not try to approach this with tableStyle. There are no public configurations as of now.

It's important to note an undeclared padding defaults to 0.

struct ContentTable: View {
    var items: [ContentItem]
    
    @State var selection = Set<ContentItem.ID>()
    
    var body: some View {
        Table(selection: $selection) {
            TableColumn("Name") {
                Text($0.name).padding(.vertical, 8) // <--- THIS WILL TAKE PRECEDENCE.
            }.width(min: 200, ideal: 250)

            TableColumn("Description") {
                Text("\($0.description)").padding(.vertical, 16)  // <--- THIS WILL BE INEFFECTIVE.
            }
        } rows: {
            ForEach(items) {
                TableRow($0)
            }
        }
        .tableStyle(.inset(alternatesRowBackgrounds: true))
    }
}
Yesman answered 26/3, 2022 at 17:37 Comment(7)
I tried this but to no avail. To be sure I set a target to macOS 12.13, cleaned and rebuilt, increase the padding size... same. swift TableColumn("Name") {_ in Text("TEST").padding(.vertical, 50) }.width(min: 200, ideal: 250) Tilney
OH, interesting.... I actually have a implicit final column TableColumn("Description", value: \.description), which when included prevents the padding. Remove it does as you said @YesmanTilney
@Tilney That makes sense because initializing TableColumn with a keypath does not expose the actual rendered view. It simply returns the view. So, adding the padding modifier to that TableColumn (if it even lets you) would not be rendered, and the actually returned view would likely have padding equal to zero or whatever the particular constructor's default. That's why in my example I changed the \.description column to use a trailing closure with a custom column content view. Hope this helps and good luck!Yesman
@Mkyel no this was 1 of 4 TableColumns, and was the last. Just the use of it in the Table block cause any other TableColumn with a custom view to not work as intended. Another note - the solution put forward does work for rows with contents, but not those on screen without. That is, if a Table is able to show 20 rows and I only have data for 4, only the 4 with data will increase their size.Tilney
If by "to not work as intended" you mean filtering by the header being lost, that was not part of your question. Feel free to start another SO question and I can address that. If I understand your second point correctly, you could simply put "empty content" (e.g. whitespace in TextView or EmptyView) in those columns based on a condition. That would ensure partial data rows, or even empty rows (personally would omit those), conform to the height of the rest of the columns.Yesman
My point was not about sorting, but the row height not working when including a single TableColumn that uses a key path - seems like an bug. The code I posted here and what I have in my project is different. I was having trouble with row heights because 3 of my TableColumn definitions were as described here (custom views for each cell) and the final was using a key path and an implicit view for the cell... New issue is that the TableView only has 4 rows of data but shows 20, but rows 5-20 do not have data and therefore do not support row height changes.Tilney
@Tilney Yup. For your second point, you have to set a dynamic height of the overall TableView. I don't know if there is an official way, but you can manually set by the array count in a few different ways. If you want to start another question, I can throw out a couple answers.Yesman

© 2022 - 2024 — McMap. All rights reserved.