Skip to content

Instantly share code, notes, and snippets.

@mdb1
Last active October 9, 2023 20:16
Show Gist options
  • Select an option

  • Save mdb1/2080d31fe626dd42b17f97d2b9337db6 to your computer and use it in GitHub Desktop.

Select an option

Save mdb1/2080d31fe626dd42b17f97d2b9337db6 to your computer and use it in GitHub Desktop.

Revisions

  1. mdb1 revised this gist Oct 9, 2023. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions AdaptableStack.swift
    Original file line number Diff line number Diff line change
    @@ -66,11 +66,11 @@ private extension AdaptableStack {
    var layout: AnyLayout {
    switch axis {
    case .vertical:
    return size > threshold
    return size > sizeThreshold
    ? AnyLayout(HStackLayout(alignment: hAlignment, spacing: hSpacing))
    : AnyLayout(VStackLayout(alignment: vAlignment, spacing: vSpacing))
    case .horizontal:
    return size > threshold
    return size > sizeThreshold
    ? AnyLayout(VStackLayout(alignment: vAlignment, spacing: vSpacing))
    : AnyLayout(HStackLayout(alignment: hAlignment, spacing: hSpacing))
    }
  2. mdb1 revised this gist Oct 9, 2023. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions AdaptableStack.swift
    Original file line number Diff line number Diff line change
    @@ -66,11 +66,11 @@ private extension AdaptableStack {
    var layout: AnyLayout {
    switch axis {
    case .vertical:
    return isZoomed(size, threshold: sizeThreshold)
    return size > threshold
    ? AnyLayout(HStackLayout(alignment: hAlignment, spacing: hSpacing))
    : AnyLayout(VStackLayout(alignment: vAlignment, spacing: vSpacing))
    case .horizontal:
    return isZoomed(size, threshold: sizeThreshold)
    return size > threshold
    ? AnyLayout(VStackLayout(alignment: vAlignment, spacing: vSpacing))
    : AnyLayout(HStackLayout(alignment: hAlignment, spacing: hSpacing))
    }
  3. mdb1 revised this gist Oct 9, 2023. 1 changed file with 8 additions and 8 deletions.
    16 changes: 8 additions & 8 deletions AdaptableStack.swift
    Original file line number Diff line number Diff line change
    @@ -10,11 +10,11 @@ struct AdaptableStack<Content>: View where Content: View {
    /// Alignment of children along the X-axis for vertical stack.
    private var vAlignment: HorizontalAlignment
    /// Spacing between children for vertical stack.
    private var vSpacing: CGFloat
    private var vSpacing: CGFloat?
    /// Alignment of children along the Y-axis for horizontal stack.
    private var hAlignment: VerticalAlignment
    /// Spacing between children for horizontal stack.
    private var hSpacing: CGFloat
    private var hSpacing: CGFloat?
    /// Closure providing the stack's content.
    private var content: () -> Content

    @@ -24,17 +24,17 @@ struct AdaptableStack<Content>: View where Content: View {
    /// - axis: The primary axis for the stack (`vertical` or `horizontal`).
    /// - sizeThreshold: The size above which to switch the axis. Default is `.accessibility1`.
    /// - vAlignment: The X-axis alignment for a vertical stack. Default is `.center`.
    /// - vSpacing: The spacing for a vertical stack. Default is `8`.
    /// - vSpacing: The spacing for a vertical stack. Default is `nil`.
    /// - hAlignment: The Y-axis alignment for a horizontal stack. Default is `.center`.
    /// - hSpacing: The spacing for a horizontal stack. Default is `8`.
    /// - hSpacing: The spacing for a horizontal stack. Default is `nil`.
    /// - content: The content of the stack.
    init(
    _ axis: StackAxis,
    sizeThreshold: DynamicTypeSize = .accessibility1,
    vAlignment: HorizontalAlignment = .center,
    vSpacing: CGFloat = 8,
    vSpacing: CGFloat? = nil,
    hAlignment: VerticalAlignment = .center,
    hSpacing: CGFloat = 8,
    hSpacing: CGFloat? = nil,
    @ViewBuilder content: @escaping () -> Content
    ) {
    self.axis = axis
    @@ -66,11 +66,11 @@ private extension AdaptableStack {
    var layout: AnyLayout {
    switch axis {
    case .vertical:
    return size > sizeThreshold
    return isZoomed(size, threshold: sizeThreshold)
    ? AnyLayout(HStackLayout(alignment: hAlignment, spacing: hSpacing))
    : AnyLayout(VStackLayout(alignment: vAlignment, spacing: vSpacing))
    case .horizontal:
    return size > sizeThreshold
    return isZoomed(size, threshold: sizeThreshold)
    ? AnyLayout(VStackLayout(alignment: vAlignment, spacing: vSpacing))
    : AnyLayout(HStackLayout(alignment: hAlignment, spacing: hSpacing))
    }
  4. mdb1 created this gist Oct 7, 2023.
    78 changes: 78 additions & 0 deletions AdaptableStack.swift
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,78 @@
    import SwiftUI

    /// An adaptable stack view that switches between `HStack` and `VStack` based on the dynamic text size.
    struct AdaptableStack<Content>: View where Content: View {
    @Environment(\.dynamicTypeSize) private var size: DynamicTypeSize
    /// The primary axis along which the stack arranges its children.
    private var axis: StackAxis
    /// The dynamic type size threshold above which the stack axis will switch.
    private var sizeThreshold: DynamicTypeSize
    /// Alignment of children along the X-axis for vertical stack.
    private var vAlignment: HorizontalAlignment
    /// Spacing between children for vertical stack.
    private var vSpacing: CGFloat
    /// Alignment of children along the Y-axis for horizontal stack.
    private var hAlignment: VerticalAlignment
    /// Spacing between children for horizontal stack.
    private var hSpacing: CGFloat
    /// Closure providing the stack's content.
    private var content: () -> Content

    /// Creates an `AdaptableStack` with the given properties.
    ///
    /// - Parameters:
    /// - axis: The primary axis for the stack (`vertical` or `horizontal`).
    /// - sizeThreshold: The size above which to switch the axis. Default is `.accessibility1`.
    /// - vAlignment: The X-axis alignment for a vertical stack. Default is `.center`.
    /// - vSpacing: The spacing for a vertical stack. Default is `8`.
    /// - hAlignment: The Y-axis alignment for a horizontal stack. Default is `.center`.
    /// - hSpacing: The spacing for a horizontal stack. Default is `8`.
    /// - content: The content of the stack.
    init(
    _ axis: StackAxis,
    sizeThreshold: DynamicTypeSize = .accessibility1,
    vAlignment: HorizontalAlignment = .center,
    vSpacing: CGFloat = 8,
    hAlignment: VerticalAlignment = .center,
    hSpacing: CGFloat = 8,
    @ViewBuilder content: @escaping () -> Content
    ) {
    self.axis = axis
    self.sizeThreshold = sizeThreshold
    self.vAlignment = vAlignment
    self.vSpacing = vSpacing
    self.hAlignment = hAlignment
    self.hSpacing = hSpacing
    self.content = content
    }

    var body: some View {
    layout {
    content()
    }
    }
    }

    extension AdaptableStack {
    /// Enum to represent the primary axis for the stack.
    enum StackAxis {
    case vertical
    case horizontal
    }
    }

    private extension AdaptableStack {
    /// Determines the layout to use based on the `axis` and `size`.
    var layout: AnyLayout {
    switch axis {
    case .vertical:
    return size > sizeThreshold
    ? AnyLayout(HStackLayout(alignment: hAlignment, spacing: hSpacing))
    : AnyLayout(VStackLayout(alignment: vAlignment, spacing: vSpacing))
    case .horizontal:
    return size > sizeThreshold
    ? AnyLayout(VStackLayout(alignment: vAlignment, spacing: vSpacing))
    : AnyLayout(HStackLayout(alignment: hAlignment, spacing: hSpacing))
    }
    }
    }