Skip to content

Instantly share code, notes, and snippets.

@marcpalmer
Created March 2, 2023 23:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save marcpalmer/0d83b47218939852e1e4fbc91be3b30b to your computer and use it in GitHub Desktop.
Save marcpalmer/0d83b47218939852e1e4fbc91be3b30b to your computer and use it in GitHub Desktop.
Simple Table/Row/Column views
//
// 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