How can I display tabular data with SwiftUI on iPhone?
Asked Answered
A

2

7

I'm working on an app for my local sports league.

One view will be the current standings, with several fields on each row: Name of team, Games Played, Points, etc. I want the Teams column to be left-aligned, the other columns to be right-aligned.

It seems the best answer is SwiftUI's Table(), but on iPhone, it only displays the first column.

I've tried using an HStack{} with Text():

List {
    ForEach(selectedStats()) { stats in
        HStack {
            Text (stats.name)
            Spacer()
            Text ("\(stats.totalMatches)")
            Text ("\(stats.standingsPoints)")
        }
    }
}

but I'm having difficulty getting the columns to align left or right across multiple lines in the table.

Is there a way to get Tables to work? Or how can I align my columns?

(P. S. I used the tag TableView, because there is no tag specific to Table or SwiftUI-Table. It would be nice if that could be added.)

Absolve answered 17/2, 2023 at 9:40 Comment(3)
developer.apple.com/documentation/SwiftUI/TableLookthrough
Not helpful. That just confirms that it doesn't work on iPhone, which I already stipulated.Absolve
You can customize the first column's appearance for compact width devices (iphones in portrait) to show custom table column that has all of the required columns layout, more on this in this turotial: blog.eidinger.info/swiftuis-table-view-on-ios-16Swearword
A
0

I kept researching after I posted and came across some stuff by Paul Hudson of Hacking with Swift fame.

Alignment and alignment guides

How to create a custom alignment guide

Based on those two, I came up with this:

extension HorizontalAlignment {
    enum GP: AlignmentID {
        static func defaultValue(in context: ViewDimensions) -> CGFloat {
            context[.trailing]
        }
    }
    
    static let gp = HorizontalAlignment(GP.self)
}

and then I apply

.alignmentGuide(.gp) { d in d[HorizontalAlignment.trailing] }

to each element I want to right-align.

Seems to do the trick, as well.

Absolve answered 17/2, 2023 at 15:29 Comment(0)
H
6

SwiftUI's Grid and GridRow are your friends for laying out simple content like this:

struct Stat: Identifiable, Equatable {
    var id: String { name }
    let name: String
    let totalMatches: Int
    let standingsPoints: Int
}

struct ContentView: View {
    
    let stats = [
        Stat(name: "Fred", totalMatches: 12, standingsPoints: 87),
        Stat(name: "Jim", totalMatches: 4, standingsPoints: 12),
        Stat(name: "Dave", totalMatches: 9, standingsPoints: 91)]
    
    var body: some View {
        List {
            Grid {
                GridRow {
                    Text("Name")
                    Text("Matches")
                    Text("Points")
                }
                .bold()
                Divider()
                ForEach(stats) { stat in
                    GridRow {
                        Text(stat.name)
                        Text(stat.totalMatches, format: .number)
                        Text(stat.standingsPoints, format: .number)
                    }
                    if stat != stats.last {
                        Divider()
                    }
                }
            }
        }
    }
}

enter image description here

You can tweak the layout by adding Spacer()s .gridCellAnchor modifiers, e.g.

var body: some View {
    List {
        Grid {
            GridRow {
                Text("Name"). // UnitPoint(x: 1, y: 0.5) = align right
                    .gridCellAnchor(UnitPoint(x: 1, y: 0.5))
                Spacer()
                Text("Matches") // UnitPoint(x: 0, y: 0.5) = align left
                    .gridCellAnchor(UnitPoint(x: 0, y: 0.5))
                Text("Points")
                    .gridCellAnchor(UnitPoint(x: 0, y: 0.5))
            }
            .bold()
            Divider()
            ForEach(stats) { stat in
                GridRow {
                    Text(stat.name)
                        .gridCellAnchor(UnitPoint(x: 1, y: 0.5))
                    Spacer()
                    Text(stat.totalMatches, format: .number)
                        .gridCellAnchor(UnitPoint(x: 0, y: 0.5))
                    Text(stat.standingsPoints, format: .number)
                        .gridCellAnchor(UnitPoint(x: 0, y: 0.5))
                }
                if stat != stats.last {
                    Divider()
                }
            }
        }
    }
}

enter image description here

Hbeam answered 17/2, 2023 at 11:2 Comment(2)
This looks very promising. Thanks! I found another option from Paul Hudson's Hacking with Swift series....Absolve
What if I have to support iOS 15+?Amenable
A
0

I kept researching after I posted and came across some stuff by Paul Hudson of Hacking with Swift fame.

Alignment and alignment guides

How to create a custom alignment guide

Based on those two, I came up with this:

extension HorizontalAlignment {
    enum GP: AlignmentID {
        static func defaultValue(in context: ViewDimensions) -> CGFloat {
            context[.trailing]
        }
    }
    
    static let gp = HorizontalAlignment(GP.self)
}

and then I apply

.alignmentGuide(.gp) { d in d[HorizontalAlignment.trailing] }

to each element I want to right-align.

Seems to do the trick, as well.

Absolve answered 17/2, 2023 at 15:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.