Skip to content

Instantly share code, notes, and snippets.

@StefKors
Created April 14, 2025 09:18
Show Gist options
  • Save StefKors/e2d1da9eb6cf29cb19a36510faf6533e to your computer and use it in GitHub Desktop.
Save StefKors/e2d1da9eb6cf29cb19a36510faf6533e to your computer and use it in GitHub Desktop.
//
// DividedStack.swift
// based on: https://github.com/aramayyes/Popovers/blob/54728a9ca199ffbffe444d5b04a9354f6a02da7c/Sources/Templates/Views.swift#L14
//
// Created by Stef Kors on 19/12/2024.
//
import SwiftUI
/// A vertical stack that adds separators
/// From https://movingparts.io/variadic-views-in-swiftui
struct DividedVStack<Content: View>: View {
var alignment: HorizontalAlignment
var spacing: CGFloat?
var leadingMargin: CGFloat
var trailingMargin: CGFloat
var color: Color?
var content: Content
public init(
alignment: HorizontalAlignment = .center,
spacing: CGFloat? = nil,
leadingMargin: CGFloat = 0,
trailingMargin: CGFloat = 0,
color: Color? = nil,
@ViewBuilder content: () -> Content
) {
self.alignment = alignment
self.spacing = spacing
self.leadingMargin = leadingMargin
self.trailingMargin = trailingMargin
self.color = color
self.content = content()
}
public var body: some View {
_VariadicView.Tree(
DividedVStackLayout(
alignment: alignment,
spacing: spacing,
leadingMargin: leadingMargin,
trailingMargin: trailingMargin,
color: color
)
) {
content
}
}
}
struct DividedVStackLayout: _VariadicView_UnaryViewRoot {
var alignment: HorizontalAlignment
var spacing: CGFloat?
var leadingMargin: CGFloat
var trailingMargin: CGFloat
var color: Color?
@ViewBuilder
public func body(children: _VariadicView.Children) -> some View {
let last = children.last?.id
VStack(alignment: alignment, spacing: spacing) {
ForEach(children) { child in
child
if child.id != last {
Divider()
.foregroundStyle(color ?? .primary)
.padding(.leading, leadingMargin)
.padding(.trailing, trailingMargin)
}
}
}
}
}
/// A horizontal stack that adds separators
struct DividedHStack<Content: View>: View {
var alignment: VerticalAlignment
var spacing: CGFloat?
var topMargin: CGFloat
var bottomMargin: CGFloat
var color: Color?
var content: Content
public init(
alignment: VerticalAlignment = .center,
spacing: CGFloat? = nil,
topMargin: CGFloat = 0,
bottomMargin: CGFloat = 0,
color: Color? = nil,
@ViewBuilder content: () -> Content
) {
self.alignment = alignment
self.spacing = spacing
self.topMargin = topMargin
self.bottomMargin = bottomMargin
self.color = color
self.content = content()
}
public var body: some View {
_VariadicView.Tree(
DividedHStackLayout(
alignment: alignment,
spacing: spacing,
topMargin: topMargin,
bottomMargin: bottomMargin,
color: color
)
) {
content
}
}
}
struct DividedHStackLayout: _VariadicView_UnaryViewRoot {
var alignment: VerticalAlignment
var spacing: CGFloat?
var topMargin: CGFloat
var bottomMargin: CGFloat
var color: Color?
@ViewBuilder
public func body(children: _VariadicView.Children) -> some View {
let last = children.last?.id
HStack(alignment: alignment, spacing: spacing) {
ForEach(children) { child in
child
if child.id != last {
Divider()
.foregroundStyle(color ?? .primary)
.padding(.top, topMargin)
.padding(.bottom, bottomMargin)
}
}
}
}
}
#Preview("Horizontal") {
let item: some View = Image(systemName: "scribble.variable").padding()
DividedHStack(color: .red) {
item
item
item
}
.frame(maxHeight: 20)
.scenePadding()
}
#Preview("Vertical") {
let item: some View = Image(systemName: "scribble.variable").padding()
DividedVStack(color: .red) {
item
item
item
}
.frame(maxWidth: 20)
.scenePadding()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment