Skip to content

Instantly share code, notes, and snippets.

@mayoff
Created November 5, 2021 16:28
Show Gist options
  • Save mayoff/260e019f307dfcb55f00e40a227a4225 to your computer and use it in GitHub Desktop.
Save mayoff/260e019f307dfcb55f00e40a227a4225 to your computer and use it in GitHub Desktop.

Revisions

  1. mayoff created this gist Nov 5, 2021.
    134 changes: 134 additions & 0 deletions TableDemo.swift
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,134 @@
    import SwiftUI

    fileprivate struct WidthPreferenceKey: PreferenceKey {
    static var defaultValue: [AnyHashable: CGFloat] { [:] }

    static func reduce(value: inout [AnyHashable : CGFloat], nextValue: () -> [AnyHashable : CGFloat]) {
    value.merge(nextValue(), uniquingKeysWith: { max($0, $1) })
    }
    }

    extension WidthPreferenceKey: EnvironmentKey { }

    extension EnvironmentValues {
    fileprivate var widthPreference: WidthPreferenceKey.Value {
    get { self[WidthPreferenceKey.self] }
    set { self[WidthPreferenceKey.self] = newValue }
    }
    }

    extension View {
    public func widthPreference<Domain: Hashable>(_ key: Domain) -> some View {
    return self.modifier(WidthPreferenceModifier(key: key))
    }
    }

    fileprivate struct WidthPreferenceModifier: ViewModifier {
    @Environment(\.widthPreference) var widthPreference
    var key: AnyHashable

    func body(content: Content) -> some View {
    content
    .fixedSize(horizontal: true, vertical: false)
    .background(GeometryReader { proxy in
    Color.clear
    .preference(key: WidthPreferenceKey.self, value: [key: proxy.size.width])
    })
    .frame(width: widthPreference[key])
    }
    }

    public struct WidthPreferenceDomain<Content: View>: View {
    @State private var widthPreference: WidthPreferenceKey.Value = [:]
    private var content: Content

    public init(@ViewBuilder content: () -> Content) {
    self.content = content()
    }

    public var body: some View {
    content
    .environment(\.widthPreference, widthPreference)
    .onPreferenceChange(WidthPreferenceKey.self) { widthPreference = $0 }
    }
    }

    struct ContentView: View {
    var body: some View {
    VStack(spacing: 0) {
    ZStack {
    TitleBackground()
    Text("Clients")
    .foregroundColor(.white)
    }
    TableView()
    Spacer()
    }
    }
    }

    enum ColumnId: Hashable {
    case name
    case balance
    case currency
    }

    struct TableView: View {
    var body: some View {
    WidthPreferenceDomain {
    VStack(spacing: 0) {
    HStack(spacing: 30) {
    Text("Name")
    .widthPreference(ColumnId.name)
    Text("Balance")
    .widthPreference(ColumnId.balance)
    Text("Currency")
    .widthPreference(ColumnId.currency)
    Spacer()
    }
    .frame(maxWidth:.infinity)
    .padding(12)
    .background(Color(#colorLiteral(red: 0.9332349896, green: 0.9333916306, blue: 0.9332130551, alpha: 1)))
    ForEach(0 ..< 4) { _ in
    RowView()
    }
    }
    }
    }
    }

    struct RowView : View {
    var body: some View {
    HStack(spacing: 30) {
    Text("John")
    .widthPreference(ColumnId.name)
    Text("$5300")
    .widthPreference(ColumnId.balance)
    Text("EUR")
    .widthPreference(ColumnId.currency)
    Spacer()
    }
    .padding(12)
    }
    }

    struct TitleBackground: View {
    var body: some View {
    ZStack(alignment: .bottom){
    Rectangle()
    .frame(maxWidth: .infinity, maxHeight: 60)
    .foregroundColor(.red)
    .cornerRadius(15)
    //We only need the top corners rounded, so we embed another rectangle to the bottom.
    Rectangle()
    .frame(maxWidth: .infinity, maxHeight: 15)
    .foregroundColor(.red)
    }
    }
    }

    struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
    ContentView()
    }
    }