Created
April 14, 2025 09:18
-
-
Save StefKors/e2d1da9eb6cf29cb19a36510faf6533e to your computer and use it in GitHub Desktop.
This file contains hidden or 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
// | |
// 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