'Visualize Table in SwiftUI
How can I visualize this data as table in SwiftUI:
I have an invoice object with pages and tables and cells.
The cells do have information about rowIndex and columnIndex:
struct Cell: Codable, Hashable, Identifiable {
let id: UUID = UUID()
let rowIndex, columnIndex: Int
let text: String
let boundingBox: [Double]
let isHeader: Bool?
}
Currently I have no better idea then this do get a "new" row:
if !invoice.invoice.isEmpty {
ScrollView{
HStack {
ForEach (invoice.invoice) {invoice in
ForEach (invoice.analyzeResult.pageResults) {pageresult in
ForEach (pageresult.tables) {table in
ForEach (table.cells) {cell in
if (cell.rowIndex == 0) {
Text(cell.text)
}
}
}
}
}
}
HStack {
ForEach (invoice.invoice) {invoice in
ForEach (invoice.analyzeResult.pageResults) {pageresult in
ForEach (pageresult.tables) {table in
ForEach (table.cells) {cell in
if (cell.rowIndex == 1) {
Text(cell.text)
}
}
}
}
}
}
}
}
Any idea how to solve this?
Thanks a lot
Solution 1:[1]
You can use either a combination of VStack and HStack or a LazyVGrid, the latter seems more appropriate. In both cases you have to find the nr of columns (and rows for 1. case).
Here is an example with both approaches:
// create dummy data
let tableData: [Cell] = {
var result = [Cell]()
for row in 0..<10 {
for col in 0..<5 {
result.append(Cell(rowIndex: row, columnIndex: col, text: "cell \(row), \(col)", boundingBox: [], isHeader: nil))
}
}
return result
}()
struct ContentView: View {
// find row & col nrs
let rowNr = tableData.max(by: {$0.rowIndex < $1.rowIndex})?.rowIndex ?? 0
let colNr = tableData.max(by: {$0.columnIndex < $1.columnIndex})?.columnIndex ?? 0
var body: some View {
VStack {
ScrollView {
// Option 1: VStack and HStack
VStack {
ForEach(0..<rowNr+1) { row in
HStack {
ForEach(0..<colNr+1) { col in
// find cell with row + col numbers
if let cell = tableData.first(where: { $0.rowIndex == row && $0.columnIndex == col }) {
Text(cell.text)
}
}
}
}
}
Divider()
// Option 2: LazyVGrid View
let columns = [GridItem].init(repeating: GridItem(.flexible(minimum: 10)), count: colNr+1)
LazyVGrid(columns: columns) {
ForEach(tableData
.sorted(by: {$0.columnIndex < $1.columnIndex})
.sorted(by: {$0.rowIndex < $1.rowIndex}))
{ cell in
Text(cell.text)
}
}
}
}
}
}
EDIT: As @loremipsum pointed out there might be the case, that there is no value for every combination of row/columns. In this case you could map the data to an array first, filling the empty data points:
func dataMappedToArray() -> [Cell] {
let rowNr = tableData.reduce(0, { max($0, $1.rowIndex) })
let colNr = tableData.reduce(0, { max($0, $1.columnIndex) })
var result = [Cell]()
for row in 0...rowNr {
for col in 0...colNr {
if let cell = tableData.first(where: { $0.rowIndex == row && $0.columnIndex == col }) {
result.append(cell)
} else {
// "empty" cell
result.append(Cell(rowIndex: row, columnIndex: col, text: "–", boundingBox: [], isHeader: nil) )
}
}
}
return result
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
