From 4cbb96f7e202021b518ade064cd5de4db0c657b0 Mon Sep 17 00:00:00 2001 From: Daniel Kloeck Date: Sat, 3 Dec 2022 14:36:17 +0100 Subject: [PATCH 1/3] feat: extract and reuse the line mangement code --- .../InternalWrappingHStack.swift | 63 ++++--------------- Sources/WrappingHStack/LineManager.swift | 58 +++++++++++++++++ Sources/WrappingHStack/WrappingHStack.swift | 4 +- 3 files changed, 74 insertions(+), 51 deletions(-) create mode 100644 Sources/WrappingHStack/LineManager.swift diff --git a/Sources/WrappingHStack/InternalWrappingHStack.swift b/Sources/WrappingHStack/InternalWrappingHStack.swift index e3aad32..fa4c4da 100644 --- a/Sources/WrappingHStack/InternalWrappingHStack.swift +++ b/Sources/WrappingHStack/InternalWrappingHStack.swift @@ -6,40 +6,23 @@ struct InternalWrappingHStack: View { let alignment: HorizontalAlignment let spacing: WrappingHStack.Spacing let content: [WrappingHStack.ViewType] - let firstItemOfEachLine: [Int] let lineSpacing: CGFloat + let lineManager: LineManager - init(width: CGFloat, alignment: HorizontalAlignment, spacing: WrappingHStack.Spacing, lineSpacing: CGFloat, content: [WrappingHStack.ViewType]) { + init(width: CGFloat, alignment: HorizontalAlignment, spacing: WrappingHStack.Spacing, lineSpacing: CGFloat, content: [WrappingHStack.ViewType], lineManager: LineManager) { self.width = width self.alignment = alignment self.spacing = spacing self.lineSpacing = lineSpacing self.content = content + self.lineManager = lineManager - firstItemOfEachLine = content - .enumerated() - .reduce((firstItemOfEachLine: [], currentLineWidth: width)) { (result, contentIterator) -> (firstItemOfEachLine: [Int], currentLineWidth: CGFloat) in - var (firstItemOfEachLine, currentLineWidth) = result - - switch contentIterator.element { - case .newLine: - return (firstItemOfEachLine + [contentIterator.offset], width) - case .any(let anyView) where Self.isVisible(view: anyView): - let itemWidth = Self.getWidth(of: anyView) - if result.currentLineWidth + itemWidth + spacing.minSpacing > width { - currentLineWidth = itemWidth - firstItemOfEachLine.append(contentIterator.offset) - } else { - currentLineWidth += itemWidth + spacing.minSpacing - } - return (firstItemOfEachLine, currentLineWidth) - default: - return result - } - }.0 + if !lineManager.isSetUp { + lineManager.setup(content: content, width: width, spacing: spacing) + } } - static func getWidth(of anyView: AnyView) -> Double { + @inline(__always) static func getWidth(of anyView: AnyView) -> Double { #if os(iOS) let hostingController = UIHostingController(rootView: HStack { anyView }) #else @@ -48,51 +31,31 @@ struct InternalWrappingHStack: View { return hostingController.sizeThatFits(in: CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude)).width } - var totalLines: Int { - firstItemOfEachLine.count - } - - func startOf(line i: Int) -> Int { - firstItemOfEachLine[i] - } - - func endOf(line i: Int) -> Int { - i == totalLines - 1 ? content.count - 1 : firstItemOfEachLine[i + 1] - 1 - } - - func hasExactlyOneElement(line i: Int) -> Bool { - startOf(line: i) == endOf(line: i) - } - func shouldHaveSideSpacers(line i: Int) -> Bool { if case .constant = spacing { return true } - if case .dynamic = spacing, hasExactlyOneElement(line: i) { + if case .dynamic = spacing, lineManager.hasExactlyOneElement(line: i) { return true } return false } @inline(__always) static func isVisible(view: AnyView) -> Bool { -#if os(iOS) - return UIHostingController(rootView: view).sizeThatFits(in: CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude)).width > 0 -#else - return NSHostingController(rootView: view).sizeThatFits(in: CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude)).width > 0 -#endif + getWidth(of: view) > 0 } var body: some View { VStack(alignment: alignment, spacing: lineSpacing) { - ForEach(0 ..< totalLines, id: \.self) { lineIndex in + ForEach(0 ..< lineManager.totalLines, id: \.self) { lineIndex in HStack(spacing: 0) { if alignment == .center || alignment == .trailing, shouldHaveSideSpacers(line: lineIndex) { Spacer(minLength: 0) } - ForEach(startOf(line: lineIndex) ... endOf(line: lineIndex), id: \.self) { + ForEach(lineManager.startOf(line: lineIndex) ... lineManager.endOf(line: lineIndex), id: \.self) { if case .dynamicIncludingBorders = spacing, - startOf(line: lineIndex) == $0 + lineManager.startOf(line: lineIndex) == $0 { Spacer(minLength: spacing.minSpacing) } @@ -101,7 +64,7 @@ struct InternalWrappingHStack: View { anyView } - if endOf(line: lineIndex) != $0 { + if lineManager.endOf(line: lineIndex) != $0 { if case .any(let anyView) = content[$0], !Self.isVisible(view: anyView) { } else { if case .constant(let exactSpacing) = spacing { Spacer(minLength: 0) diff --git a/Sources/WrappingHStack/LineManager.swift b/Sources/WrappingHStack/LineManager.swift new file mode 100644 index 0000000..bb11075 --- /dev/null +++ b/Sources/WrappingHStack/LineManager.swift @@ -0,0 +1,58 @@ +import Foundation + +/// This class calculates which items should be on which lines +class LineManager { + private var content: [WrappingHStack.ViewType]! + private var spacing: WrappingHStack.Spacing! + private var width: CGFloat! + + lazy var firstItemOfEachLine: [Int] = { + content + .enumerated() + .reduce((firstItemOfEachLine: [], currentLineWidth: width)) { (result, contentIterator) -> (firstItemOfEachLine: [Int], currentLineWidth: CGFloat) in + var (firstItemOfEachLine, currentLineWidth) = result + + switch contentIterator.element { + case .newLine: + return (firstItemOfEachLine + [contentIterator.offset], width) + case .any(let anyView) where InternalWrappingHStack.isVisible(view: anyView): + let itemWidth = InternalWrappingHStack.getWidth(of: anyView) + if result.currentLineWidth + itemWidth + spacing.minSpacing > width { + currentLineWidth = itemWidth + firstItemOfEachLine.append(contentIterator.offset) + } else { + currentLineWidth += itemWidth + spacing.minSpacing + } + return (firstItemOfEachLine, currentLineWidth) + default: + return result + } + }.0 + }() + + var isSetUp: Bool { + width != nil + } + + func setup(content: [WrappingHStack.ViewType], width: CGFloat, spacing: WrappingHStack.Spacing) { + self.content = content + self.width = width + self.spacing = spacing + } + + var totalLines: Int { + firstItemOfEachLine.count + } + + func startOf(line i: Int) -> Int { + firstItemOfEachLine[i] + } + + func endOf(line i: Int) -> Int { + i == totalLines - 1 ? content.count - 1 : firstItemOfEachLine[i + 1] - 1 + } + + func hasExactlyOneElement(line i: Int) -> Bool { + startOf(line: i) == endOf(line: i) + } +} diff --git a/Sources/WrappingHStack/WrappingHStack.swift b/Sources/WrappingHStack/WrappingHStack.swift index e28f851..2974143 100644 --- a/Sources/WrappingHStack/WrappingHStack.swift +++ b/Sources/WrappingHStack/WrappingHStack.swift @@ -48,6 +48,7 @@ public struct WrappingHStack: View { let alignment: HorizontalAlignment let spacing: Spacing let lineSpacing: CGFloat + let lineManager = LineManager() @State private var height: CGFloat = 0 public var body: some View { @@ -57,7 +58,8 @@ public struct WrappingHStack: View { alignment: alignment, spacing: spacing, lineSpacing: lineSpacing, - content: items + content: items, + lineManager: lineManager ) .anchorPreference( key: HeightPreferenceKey.self, From 3a75310ff1c368f3a34badda8b4be9153935e4bf Mon Sep 17 00:00:00 2001 From: Daniel Kloeck Date: Sat, 3 Dec 2022 14:49:49 +0100 Subject: [PATCH 2/3] feat: extract and reuse the content management functionality of InternalWrappingHStack --- Sources/WrappingHStack/ContentManager.swift | 45 ++++++ .../InternalWrappingHStack.swift | 30 +--- Sources/WrappingHStack/LineManager.swift | 51 +++---- Sources/WrappingHStack/NewLine.swift | 1 + Sources/WrappingHStack/WrappingHStack.swift | 140 ++++++++---------- .../project.pbxproj | 2 - .../project.pbxproj | 2 - .../WrappingHStackExampleApp.swift | 12 +- 8 files changed, 148 insertions(+), 135 deletions(-) create mode 100644 Sources/WrappingHStack/ContentManager.swift diff --git a/Sources/WrappingHStack/ContentManager.swift b/Sources/WrappingHStack/ContentManager.swift new file mode 100644 index 0000000..aeaedf7 --- /dev/null +++ b/Sources/WrappingHStack/ContentManager.swift @@ -0,0 +1,45 @@ +import SwiftUI + +/// This class manages content and the calculation of their widths (reusing it). +/// It should be reused whenever possible. +class ContentManager { + enum ViewType { + case any(AnyView) + case newLine + + init(rawView: V) { + switch rawView { + case is NewLine: self = .newLine + default: self = .any(AnyView(rawView)) + } + } + } + + let items: [ViewType] + lazy var widths: [Double] = { + items.map { + if case let .any(anyView) = $0 { + return Self.getWidth(of: anyView) + } else { + return 0 + } + } + }() + + init(items: [ViewType]) { + self.items = items + } + + @inline(__always) private static func getWidth(of anyView: AnyView) -> Double { +#if os(iOS) + let hostingController = UIHostingController(rootView: HStack { anyView }) +#else + let hostingController = NSHostingController(rootView: HStack { anyView }) +#endif + return hostingController.sizeThatFits(in: CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude)).width + } + + func isVisible(viewIndex: Int) -> Bool { + widths[viewIndex] > 0 + } +} diff --git a/Sources/WrappingHStack/InternalWrappingHStack.swift b/Sources/WrappingHStack/InternalWrappingHStack.swift index fa4c4da..cda01a5 100644 --- a/Sources/WrappingHStack/InternalWrappingHStack.swift +++ b/Sources/WrappingHStack/InternalWrappingHStack.swift @@ -1,35 +1,25 @@ import SwiftUI -// based on https://swiftui.diegolavalle.com/posts/linewrapping-stacks/ +/// This View draws the WrappingHStack content taking into account the passed width, alignment and spacings. +/// Note that the passed LineManager and ContentManager should be reused whenever possible. struct InternalWrappingHStack: View { - let width: CGFloat let alignment: HorizontalAlignment let spacing: WrappingHStack.Spacing - let content: [WrappingHStack.ViewType] let lineSpacing: CGFloat let lineManager: LineManager + let contentManager: ContentManager - init(width: CGFloat, alignment: HorizontalAlignment, spacing: WrappingHStack.Spacing, lineSpacing: CGFloat, content: [WrappingHStack.ViewType], lineManager: LineManager) { - self.width = width + init(width: CGFloat, alignment: HorizontalAlignment, spacing: WrappingHStack.Spacing, lineSpacing: CGFloat, lineManager: LineManager, contentManager: ContentManager) { self.alignment = alignment self.spacing = spacing self.lineSpacing = lineSpacing - self.content = content + self.contentManager = contentManager self.lineManager = lineManager if !lineManager.isSetUp { - lineManager.setup(content: content, width: width, spacing: spacing) + lineManager.setup(contentManager: contentManager, width: width, spacing: spacing) } } - - @inline(__always) static func getWidth(of anyView: AnyView) -> Double { -#if os(iOS) - let hostingController = UIHostingController(rootView: HStack { anyView }) -#else - let hostingController = NSHostingController(rootView: HStack { anyView }) -#endif - return hostingController.sizeThatFits(in: CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude)).width - } func shouldHaveSideSpacers(line i: Int) -> Bool { if case .constant = spacing { @@ -40,10 +30,6 @@ struct InternalWrappingHStack: View { } return false } - - @inline(__always) static func isVisible(view: AnyView) -> Bool { - getWidth(of: view) > 0 - } var body: some View { VStack(alignment: alignment, spacing: lineSpacing) { @@ -60,12 +46,12 @@ struct InternalWrappingHStack: View { Spacer(minLength: spacing.minSpacing) } - if case .any(let anyView) = content[$0], Self.isVisible(view: anyView) { + if case .any(let anyView) = contentManager.items[$0], contentManager.isVisible(viewIndex: $0) { anyView } if lineManager.endOf(line: lineIndex) != $0 { - if case .any(let anyView) = content[$0], !Self.isVisible(view: anyView) { } else { + if case .any = contentManager.items[$0], !contentManager.isVisible(viewIndex: $0) { } else { if case .constant(let exactSpacing) = spacing { Spacer(minLength: 0) .frame(width: exactSpacing) diff --git a/Sources/WrappingHStack/LineManager.swift b/Sources/WrappingHStack/LineManager.swift index bb11075..a0de13b 100644 --- a/Sources/WrappingHStack/LineManager.swift +++ b/Sources/WrappingHStack/LineManager.swift @@ -1,41 +1,42 @@ import Foundation -/// This class calculates which items should be on which lines +/// This class is in charge of calculating which items fit on which lines. +/// It should be reused whenever possible. class LineManager { - private var content: [WrappingHStack.ViewType]! + private var contentManager: ContentManager! private var spacing: WrappingHStack.Spacing! private var width: CGFloat! lazy var firstItemOfEachLine: [Int] = { - content - .enumerated() - .reduce((firstItemOfEachLine: [], currentLineWidth: width)) { (result, contentIterator) -> (firstItemOfEachLine: [Int], currentLineWidth: CGFloat) in - var (firstItemOfEachLine, currentLineWidth) = result - - switch contentIterator.element { - case .newLine: - return (firstItemOfEachLine + [contentIterator.offset], width) - case .any(let anyView) where InternalWrappingHStack.isVisible(view: anyView): - let itemWidth = InternalWrappingHStack.getWidth(of: anyView) - if result.currentLineWidth + itemWidth + spacing.minSpacing > width { - currentLineWidth = itemWidth - firstItemOfEachLine.append(contentIterator.offset) - } else { - currentLineWidth += itemWidth + spacing.minSpacing - } - return (firstItemOfEachLine, currentLineWidth) - default: - return result + var firstOfEach = [Int]() + var currentWidth: CGFloat = width + for (index, element) in contentManager.items.enumerated() { + switch element { + case .newLine: + firstOfEach += [index] + currentWidth = width + case .any where contentManager.isVisible(viewIndex: index): + let itemWidth = contentManager.widths[index] + if currentWidth + itemWidth + spacing.minSpacing > width { + currentWidth = itemWidth + firstOfEach.append(index) + } else { + currentWidth += itemWidth + spacing.minSpacing } - }.0 + default: + break + } + } + + return firstOfEach }() var isSetUp: Bool { width != nil } - func setup(content: [WrappingHStack.ViewType], width: CGFloat, spacing: WrappingHStack.Spacing) { - self.content = content + func setup(contentManager: ContentManager, width: CGFloat, spacing: WrappingHStack.Spacing) { + self.contentManager = contentManager self.width = width self.spacing = spacing } @@ -49,7 +50,7 @@ class LineManager { } func endOf(line i: Int) -> Int { - i == totalLines - 1 ? content.count - 1 : firstItemOfEachLine[i + 1] - 1 + i == totalLines - 1 ? contentManager.items.count - 1 : firstItemOfEachLine[i + 1] - 1 } func hasExactlyOneElement(line i: Int) -> Bool { diff --git a/Sources/WrappingHStack/NewLine.swift b/Sources/WrappingHStack/NewLine.swift index b505dbb..608adbf 100644 --- a/Sources/WrappingHStack/NewLine.swift +++ b/Sources/WrappingHStack/NewLine.swift @@ -1,5 +1,6 @@ import SwiftUI +/// Use this item to force a line break in a WrappingHStack public struct NewLine: View { public init() { } public let body = Spacer(minLength: .infinity) diff --git a/Sources/WrappingHStack/WrappingHStack.swift b/Sources/WrappingHStack/WrappingHStack.swift index 2974143..34588c5 100644 --- a/Sources/WrappingHStack/WrappingHStack.swift +++ b/Sources/WrappingHStack/WrappingHStack.swift @@ -17,18 +17,6 @@ public struct WrappingHStack: View { } } - enum ViewType { - case any(AnyView) - case newLine - - init(rawView: V) { - switch rawView { - case is NewLine: self = .newLine - default: self = .any(AnyView(rawView)) - } - } - } - public enum Spacing { case constant(CGFloat) case dynamic(minSpacing: CGFloat) @@ -43,12 +31,12 @@ public struct WrappingHStack: View { } } } - - let items: [ViewType] + let alignment: HorizontalAlignment let spacing: Spacing let lineSpacing: CGFloat let lineManager = LineManager() + let contentManager: ContentManager @State private var height: CGFloat = 0 public var body: some View { @@ -58,8 +46,8 @@ public struct WrappingHStack: View { alignment: alignment, spacing: spacing, lineSpacing: lineSpacing, - content: items, - lineManager: lineManager + lineManager: lineManager, + contentManager: contentManager ) .anchorPreference( key: HeightPreferenceKey.self, @@ -81,17 +69,11 @@ public struct WrappingHStack: View { // Convenience inits that allows 10 Elements (just like HStack). // Based on https://alejandromp.com/blog/implementing-a-equally-spaced-stack-in-swiftui-thanks-to-tupleview/ public extension WrappingHStack { - private static func viewType(from view: V) -> ViewType { - switch view { - case is NewLine: return .newLine - default: return .any(AnyView(view)) - } - } /// Instatiates a WrappingHStack /// - Parameters: /// - data: The items to show - /// - id: The `KeyPath` to use as id for the items + /// - id: The `KeyPath` to use as id for the items /// - alignment: Controls the alignment of the items. This may get /// ignored when combined with `.dynamicIncludingBorders` or /// `.dynamic` spacing. @@ -106,122 +88,122 @@ public extension WrappingHStack { self.spacing = spacing self.lineSpacing = lineSpacing self.alignment = alignment - self.items = data.map { Self.viewType(from: content($0[keyPath: id])) } + self.contentManager = ContentManager(items: data.map { ContentManager.ViewType(rawView: content($0[keyPath: id])) }) } init(alignment: HorizontalAlignment = .leading, spacing: Spacing = .constant(8), lineSpacing: CGFloat = 0, @ViewBuilder content: () -> A) { self.spacing = spacing self.lineSpacing = lineSpacing self.alignment = alignment - self.items = [Self.viewType(from: content())] + self.contentManager = ContentManager(items: [ContentManager.ViewType(rawView: content())]) } init(alignment: HorizontalAlignment = .leading, spacing: Spacing = .constant(8), lineSpacing: CGFloat = 0, @ViewBuilder content: () -> TupleView<(A, B)>) { self.spacing = spacing self.lineSpacing = lineSpacing self.alignment = alignment - self.items = [Self.viewType(from: content().value.0), - Self.viewType(from: content().value.1)] + self.contentManager = ContentManager(items: [ContentManager.ViewType(rawView: content().value.0), + ContentManager.ViewType(rawView: content().value.1)]) } init(alignment: HorizontalAlignment = .leading, spacing: Spacing = .constant(8), lineSpacing: CGFloat = 0, @ViewBuilder content: () -> TupleView<(A, B, C)>) { self.spacing = spacing self.lineSpacing = lineSpacing self.alignment = alignment - self.items = [Self.viewType(from: content().value.0), - Self.viewType(from: content().value.1), - Self.viewType(from: content().value.2)] + self.contentManager = ContentManager(items: [ContentManager.ViewType(rawView: content().value.0), + ContentManager.ViewType(rawView: content().value.1), + ContentManager.ViewType(rawView: content().value.2)]) } init(alignment: HorizontalAlignment = .leading, spacing: Spacing = .constant(8), lineSpacing: CGFloat = 0, @ViewBuilder content: () -> TupleView<(A, B, C, D)>) { self.spacing = spacing self.lineSpacing = lineSpacing self.alignment = alignment - self.items = [Self.viewType(from: content().value.0), - Self.viewType(from: content().value.1), - Self.viewType(from: content().value.2), - Self.viewType(from: content().value.3)] + self.contentManager = ContentManager(items: [ContentManager.ViewType(rawView: content().value.0), + ContentManager.ViewType(rawView: content().value.1), + ContentManager.ViewType(rawView: content().value.2), + ContentManager.ViewType(rawView: content().value.3)]) } init(alignment: HorizontalAlignment = .leading, spacing: Spacing = .constant(8), lineSpacing: CGFloat = 0, @ViewBuilder content: () -> TupleView<(A, B, C, D, E)>) { self.spacing = spacing self.lineSpacing = lineSpacing self.alignment = alignment - self.items = [Self.viewType(from: content().value.0), - Self.viewType(from: content().value.1), - Self.viewType(from: content().value.2), - Self.viewType(from: content().value.3), - Self.viewType(from: content().value.4)] + self.contentManager = ContentManager(items: [ContentManager.ViewType(rawView: content().value.0), + ContentManager.ViewType(rawView: content().value.1), + ContentManager.ViewType(rawView: content().value.2), + ContentManager.ViewType(rawView: content().value.3), + ContentManager.ViewType(rawView: content().value.4)]) } init(alignment: HorizontalAlignment = .leading, spacing: Spacing = .constant(8), lineSpacing: CGFloat = 0, @ViewBuilder content: () -> TupleView<(A, B, C, D, E, F)>) { self.spacing = spacing self.lineSpacing = lineSpacing self.alignment = alignment - self.items = [Self.viewType(from: content().value.0), - Self.viewType(from: content().value.1), - Self.viewType(from: content().value.2), - Self.viewType(from: content().value.3), - Self.viewType(from: content().value.4), - Self.viewType(from: content().value.5)] + self.contentManager = ContentManager(items: [ContentManager.ViewType(rawView: content().value.0), + ContentManager.ViewType(rawView: content().value.1), + ContentManager.ViewType(rawView: content().value.2), + ContentManager.ViewType(rawView: content().value.3), + ContentManager.ViewType(rawView: content().value.4), + ContentManager.ViewType(rawView: content().value.5)]) } init(alignment: HorizontalAlignment = .leading, spacing: Spacing = .constant(8), lineSpacing: CGFloat = 0, @ViewBuilder content: () -> TupleView<(A, B, C, D, E, F, G)>) { self.spacing = spacing self.lineSpacing = lineSpacing self.alignment = alignment - self.items = [Self.viewType(from: content().value.0), - Self.viewType(from: content().value.1), - Self.viewType(from: content().value.2), - Self.viewType(from: content().value.3), - Self.viewType(from: content().value.4), - Self.viewType(from: content().value.5), - Self.viewType(from: content().value.6)] + self.contentManager = ContentManager(items: [ContentManager.ViewType(rawView: content().value.0), + ContentManager.ViewType(rawView: content().value.1), + ContentManager.ViewType(rawView: content().value.2), + ContentManager.ViewType(rawView: content().value.3), + ContentManager.ViewType(rawView: content().value.4), + ContentManager.ViewType(rawView: content().value.5), + ContentManager.ViewType(rawView: content().value.6)]) } init(alignment: HorizontalAlignment = .leading, spacing: Spacing = .constant(8), lineSpacing: CGFloat = 0, @ViewBuilder content: () -> TupleView<(A, B, C, D, E, F, G, H)>) { self.spacing = spacing self.lineSpacing = lineSpacing self.alignment = alignment - self.items = [Self.viewType(from: content().value.0), - Self.viewType(from: content().value.1), - Self.viewType(from: content().value.2), - Self.viewType(from: content().value.3), - Self.viewType(from: content().value.4), - Self.viewType(from: content().value.5), - Self.viewType(from: content().value.6), - Self.viewType(from: content().value.7)] + self.contentManager = ContentManager(items: [ContentManager.ViewType(rawView: content().value.0), + ContentManager.ViewType(rawView: content().value.1), + ContentManager.ViewType(rawView: content().value.2), + ContentManager.ViewType(rawView: content().value.3), + ContentManager.ViewType(rawView: content().value.4), + ContentManager.ViewType(rawView: content().value.5), + ContentManager.ViewType(rawView: content().value.6), + ContentManager.ViewType(rawView: content().value.7)]) } init(alignment: HorizontalAlignment = .leading, spacing: Spacing = .constant(8), lineSpacing: CGFloat = 0, @ViewBuilder content: () -> TupleView<(A, B, C, D, E, F ,G, H, I)>) { self.spacing = spacing self.lineSpacing = lineSpacing self.alignment = alignment - self.items = [Self.viewType(from: content().value.0), - Self.viewType(from: content().value.1), - Self.viewType(from: content().value.2), - Self.viewType(from: content().value.3), - Self.viewType(from: content().value.4), - Self.viewType(from: content().value.5), - Self.viewType(from: content().value.6), - Self.viewType(from: content().value.7), - Self.viewType(from: content().value.8)] + self.contentManager = ContentManager(items: [ContentManager.ViewType(rawView: content().value.0), + ContentManager.ViewType(rawView: content().value.1), + ContentManager.ViewType(rawView: content().value.2), + ContentManager.ViewType(rawView: content().value.3), + ContentManager.ViewType(rawView: content().value.4), + ContentManager.ViewType(rawView: content().value.5), + ContentManager.ViewType(rawView: content().value.6), + ContentManager.ViewType(rawView: content().value.7), + ContentManager.ViewType(rawView: content().value.8)]) } init(alignment: HorizontalAlignment = .leading, spacing: Spacing = .constant(8), lineSpacing: CGFloat = 0, @ViewBuilder content: () -> TupleView<(A, B, C, D, E, F ,G, H, I, J)>) { self.spacing = spacing self.lineSpacing = lineSpacing self.alignment = alignment - self.items = [Self.viewType(from: content().value.0), - Self.viewType(from: content().value.1), - Self.viewType(from: content().value.2), - Self.viewType(from: content().value.3), - Self.viewType(from: content().value.4), - Self.viewType(from: content().value.5), - Self.viewType(from: content().value.6), - Self.viewType(from: content().value.7), - Self.viewType(from: content().value.8), - Self.viewType(from: content().value.9)] + self.contentManager = ContentManager(items: [ContentManager.ViewType(rawView: content().value.0), + ContentManager.ViewType(rawView: content().value.1), + ContentManager.ViewType(rawView: content().value.2), + ContentManager.ViewType(rawView: content().value.3), + ContentManager.ViewType(rawView: content().value.4), + ContentManager.ViewType(rawView: content().value.5), + ContentManager.ViewType(rawView: content().value.6), + ContentManager.ViewType(rawView: content().value.7), + ContentManager.ViewType(rawView: content().value.8), + ContentManager.ViewType(rawView: content().value.9)]) } } diff --git a/WrappingHStackExample-OSX/WrappingHStackExample.xcodeproj/project.pbxproj b/WrappingHStackExample-OSX/WrappingHStackExample.xcodeproj/project.pbxproj index 8328b55..c1ab928 100644 --- a/WrappingHStackExample-OSX/WrappingHStackExample.xcodeproj/project.pbxproj +++ b/WrappingHStackExample-OSX/WrappingHStackExample.xcodeproj/project.pbxproj @@ -267,7 +267,6 @@ CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_ASSET_PATHS = "\"WrappingHStackExample/Preview Content\""; DEVELOPMENT_TEAM = RB643832BT; ENABLE_HARDENED_RUNTIME = YES; ENABLE_PREVIEWS = YES; @@ -294,7 +293,6 @@ CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_ASSET_PATHS = "\"WrappingHStackExample/Preview Content\""; DEVELOPMENT_TEAM = RB643832BT; ENABLE_HARDENED_RUNTIME = YES; ENABLE_PREVIEWS = YES; diff --git a/WrappingHStackExample-iOS/WrappingHStackExample.xcodeproj/project.pbxproj b/WrappingHStackExample-iOS/WrappingHStackExample.xcodeproj/project.pbxproj index 62ab8a6..5f7607e 100644 --- a/WrappingHStackExample-iOS/WrappingHStackExample.xcodeproj/project.pbxproj +++ b/WrappingHStackExample-iOS/WrappingHStackExample.xcodeproj/project.pbxproj @@ -344,7 +344,6 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = RB643832BT; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = WrappingHStackExample/Info.plist; @@ -366,7 +365,6 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = RB643832BT; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = WrappingHStackExample/Info.plist; diff --git a/WrappingHStackExample-iOS/WrappingHStackExample/WrappingHStackExampleApp.swift b/WrappingHStackExample-iOS/WrappingHStackExample/WrappingHStackExampleApp.swift index 2a6c6fa..30ee503 100644 --- a/WrappingHStackExample-iOS/WrappingHStackExample/WrappingHStackExampleApp.swift +++ b/WrappingHStackExample-iOS/WrappingHStackExample/WrappingHStackExampleApp.swift @@ -23,11 +23,13 @@ struct WrappingHStackExampleApp: App { } } - NavigationView { - VStack { - NavigationLink("Long WrappingHStack") { - NavigationView { - ExampleView(exampleType: .long) + if !ProcessInfo.processInfo.arguments.contains("performanceTests_HS") { + NavigationView { + VStack { + NavigationLink("Long WrappingHStack") { + NavigationView { + ExampleView(exampleType: .long) + } } } } From ccade82660cd277abce554d390076916009af8b4 Mon Sep 17 00:00:00 2001 From: Daniel Kloeck Date: Sat, 3 Dec 2022 14:57:17 +0100 Subject: [PATCH 3/3] bump version --- WrappingHStack.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WrappingHStack.podspec b/WrappingHStack.podspec index 3794b99..4382fb8 100644 --- a/WrappingHStack.podspec +++ b/WrappingHStack.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'WrappingHStack' - s.version = '2.2.7' + s.version = '2.2.8' s.summary = 'Like HStack, but automatically positions overflowing elements on next lines.' s.description = <<-DESC WrappingHStack is a UI Element that works in a very similar way to HStack, but automatically positions overflowing elements on next lines.