Skip to content

Instantly share code, notes, and snippets.

@mjmsmith
Last active December 19, 2024 21:18
Show Gist options
  • Save mjmsmith/040ffb4a8536b61bf479ad5b0abeea6e to your computer and use it in GitHub Desktop.
Save mjmsmith/040ffb4a8536b61bf479ad5b0abeea6e to your computer and use it in GitHub Desktop.
Padding modifier for SwiftUI views.
// NOTE: Nil values implicitly or explicitly passed as arguments to padding() are ignored.
// This differs from the built-in SwiftUI version:
//
// view.padding(trailing: nil) // has no effect
// view.padding(.trailing, nil) // resets to default
//
// See below for a version that matches the built-in behavior.
extension View {
func padding(horizontal: CGFloat? = nil, vertical: CGFloat? = nil,
top: CGFloat? = nil, leading: CGFloat? = nil,
bottom: CGFloat? = nil, trailing: CGFloat? = nil) -> some View {
modifier(PaddingModifier(horizontal: horizontal, vertical: vertical,
top: top, leading: leading,
bottom: bottom, trailing: trailing))
}
}
private struct PaddingModifier: ViewModifier {
let horizontal: CGFloat?
let vertical: CGFloat?
let top: CGFloat?
let leading: CGFloat?
let bottom: CGFloat?
let trailing: CGFloat?
func body(content: Content) -> some View {
content
.modifier(EdgePaddingModifier(.horizontal, horizontal))
.modifier(EdgePaddingModifier(.vertical, vertical))
.modifier(EdgePaddingModifier(.top, top))
.modifier(EdgePaddingModifier(.leading, leading))
.modifier(EdgePaddingModifier(.bottom, bottom))
.modifier(EdgePaddingModifier(.trailing, trailing))
}
}
private struct EdgePaddingModifier: ViewModifier {
let edge: Edge.Set
let inset: CGFloat?
init(_ edge: Edge.Set, _ inset: CGFloat?) {
self.edge = edge
self.inset = inset
}
func body(content: Content) -> some View {
if let inset {
content.padding(edge, inset)
}
else {
content
}
}
}
// This version uses .nan instead of nil for default arguments to padding() so that
// it matches the built-in behavior:
//
// view.padding(trailing: nil) // resets to default
// view.padding(.trailing, nil) // resets to default
//
extension View {
func padding(horizontal: CGFloat? = .nan, vertical: CGFloat? = .nan,
top: CGFloat? = .nan, leading: CGFloat? = .nan,
bottom: CGFloat? = .nan, trailing: CGFloat? = .nan) -> some View {
modifier(PaddingModifier(horizontal: horizontal, vertical: vertical,
top: top, leading: leading,
bottom: bottom, trailing: trailing))
}
}
private struct PaddingModifier: ViewModifier {
let horizontal: CGFloat?
let vertical: CGFloat?
let top: CGFloat?
let leading: CGFloat?
let bottom: CGFloat?
let trailing: CGFloat?
func body(content: Content) -> some View {
content
.modifier(EdgePaddingModifier(.horizontal, horizontal))
.modifier(EdgePaddingModifier(.vertical, vertical))
.modifier(EdgePaddingModifier(.top, top))
.modifier(EdgePaddingModifier(.leading, leading))
.modifier(EdgePaddingModifier(.bottom, bottom))
.modifier(EdgePaddingModifier(.trailing, trailing))
}
}
private struct EdgePaddingModifier: ViewModifier {
let edge: Edge.Set
let inset: CGFloat?
init(_ edge: Edge.Set, _ inset: CGFloat?) {
self.edge = edge
self.inset = inset
}
func body(content: Content) -> some View {
if inset?.isNaN ?? false {
content
}
else {
content.padding(edge, inset)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment