Created
March 2, 2023 23:32
-
-
Save marcpalmer/0d83b47218939852e1e4fbc91be3b30b to your computer and use it in GitHub Desktop.
Simple Table/Row/Column views
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Table.swift | |
// Captionista | |
// | |
// Created by Marc Palmer on 20/03/2022. | |
// Copyright © 2022 Montana Floss Co. Ltd. All rights reserved. | |
// | |
import SwiftUI | |
struct Table<Content, ColumnIdentifier>: View where Content: View, ColumnIdentifier: Hashable { | |
let columnIdentifier: ColumnIdentifier.Type | |
@ViewBuilder let content: (_ columns: Binding<[ColumnIdentifier:CGFloat]>) -> Content | |
@State var columnWidths: [ColumnIdentifier:CGFloat] = [:] | |
var body: some View { | |
VStack(spacing: 0) { | |
content($columnWidths) | |
} | |
} | |
} | |
struct HeaderColumn<Content, ColumnIdentifier>: View where Content: View, ColumnIdentifier: Hashable { | |
let column: ColumnIdentifier | |
@Binding var columns: [ColumnIdentifier:CGFloat] | |
@ViewBuilder let content: () -> Content | |
var body: some View { | |
content() | |
.padding(.horizontal, 10) | |
.background { | |
GeometryReader { proxy in | |
Color.clear | |
.onChange(of: proxy.size) { | |
columns[column] = $0.width | |
} | |
.onAppear { | |
columns[column] = proxy.size.width | |
} | |
} | |
} | |
} | |
} | |
struct Column<Content, ColumnIdentifier>: View where Content: View, ColumnIdentifier: Hashable { | |
let column: ColumnIdentifier | |
@Binding var columns: [ColumnIdentifier: CGFloat] | |
let alignment: Alignment | |
@ViewBuilder let content: () -> Content | |
var body: some View { | |
content() | |
.padding(.horizontal, 10) | |
.frame(width: columns[column], alignment: alignment) | |
} | |
} | |
struct Row<Content>: View where Content: View { | |
let spacing: CGFloat = 10 | |
let separator: Bool | |
let pad: Bool | |
@ViewBuilder let content: () -> Content | |
init(separator: Bool = true, pad: Bool = true, @ViewBuilder content: @escaping () -> Content) { | |
self.separator = separator | |
self.content = content | |
self.pad = pad | |
} | |
var body: some View { | |
VStack(spacing: 0) { | |
HStack(spacing: 0) { | |
content() | |
} | |
.padding(.vertical, pad ? spacing : 0) | |
if separator { | |
Divider() | |
} | |
} | |
.frame(maxWidth: .infinity, alignment: .leading) | |
} | |
} | |
struct Table_Previews: PreviewProvider { | |
enum Columns: CaseIterable { | |
case label | |
case format | |
case length | |
} | |
static var previews: some View { | |
Table(columnIdentifier: Columns.self) { columns in | |
Row(pad: false) { | |
HeaderColumn(column: .label, columns: columns) { | |
Color.clear | |
.frame(height: 1) | |
} | |
HeaderColumn(column: .format, columns: columns) { | |
Text("Format") | |
} | |
HeaderColumn(column: .length, columns: columns) { | |
Text("Length") | |
} | |
} | |
Row(pad: false) { | |
Column(column: .label, columns: columns, alignment: .leading) { | |
Text("A") | |
} | |
Column(column: .format, columns: columns, alignment: .center) { | |
Text("B") | |
} | |
Column(column: .length, columns: columns, alignment: .center) { | |
Text("C") | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment