Skip to content

Commit ff31300

Browse files
authored
Documentation with the setup guide and example added
2 parents 85b076d + 4917f28 commit ff31300

File tree

4 files changed

+192
-11
lines changed

4 files changed

+192
-11
lines changed
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<Scheme
3+
LastUpgradeVersion = "1250"
4+
version = "1.3">
5+
<BuildAction
6+
parallelizeBuildables = "YES"
7+
buildImplicitDependencies = "YES">
8+
<BuildActionEntries>
9+
<BuildActionEntry
10+
buildForTesting = "YES"
11+
buildForRunning = "YES"
12+
buildForProfiling = "YES"
13+
buildForArchiving = "YES"
14+
buildForAnalyzing = "YES">
15+
<BuildableReference
16+
BuildableIdentifier = "primary"
17+
BlueprintIdentifier = "WrappingStack"
18+
BuildableName = "WrappingStack"
19+
BlueprintName = "WrappingStack"
20+
ReferencedContainer = "container:">
21+
</BuildableReference>
22+
</BuildActionEntry>
23+
<BuildActionEntry
24+
buildForTesting = "YES"
25+
buildForRunning = "YES"
26+
buildForProfiling = "NO"
27+
buildForArchiving = "NO"
28+
buildForAnalyzing = "YES">
29+
<BuildableReference
30+
BuildableIdentifier = "primary"
31+
BlueprintIdentifier = "WrappingStackTests"
32+
BuildableName = "WrappingStackTests"
33+
BlueprintName = "WrappingStackTests"
34+
ReferencedContainer = "container:">
35+
</BuildableReference>
36+
</BuildActionEntry>
37+
</BuildActionEntries>
38+
</BuildAction>
39+
<TestAction
40+
buildConfiguration = "Debug"
41+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
42+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
43+
shouldUseLaunchSchemeArgsEnv = "YES">
44+
<Testables>
45+
<TestableReference
46+
skipped = "NO">
47+
<BuildableReference
48+
BuildableIdentifier = "primary"
49+
BlueprintIdentifier = "WrappingStackTests"
50+
BuildableName = "WrappingStackTests"
51+
BlueprintName = "WrappingStackTests"
52+
ReferencedContainer = "container:">
53+
</BuildableReference>
54+
</TestableReference>
55+
</Testables>
56+
</TestAction>
57+
<LaunchAction
58+
buildConfiguration = "Debug"
59+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
60+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
61+
launchStyle = "0"
62+
useCustomWorkingDirectory = "NO"
63+
ignoresPersistentStateOnLaunch = "NO"
64+
debugDocumentVersioning = "YES"
65+
debugServiceExtension = "internal"
66+
allowLocationSimulation = "YES">
67+
</LaunchAction>
68+
<ProfileAction
69+
buildConfiguration = "Release"
70+
shouldUseLaunchSchemeArgsEnv = "YES"
71+
savedToolIdentifier = ""
72+
useCustomWorkingDirectory = "NO"
73+
debugDocumentVersioning = "YES">
74+
<MacroExpansion>
75+
<BuildableReference
76+
BuildableIdentifier = "primary"
77+
BlueprintIdentifier = "WrappingStack"
78+
BuildableName = "WrappingStack"
79+
BlueprintName = "WrappingStack"
80+
ReferencedContainer = "container:">
81+
</BuildableReference>
82+
</MacroExpansion>
83+
</ProfileAction>
84+
<AnalyzeAction
85+
buildConfiguration = "Debug">
86+
</AnalyzeAction>
87+
<ArchiveAction
88+
buildConfiguration = "Release"
89+
revealArchiveInOrganizer = "YES">
90+
</ArchiveAction>
91+
</Scheme>
48.1 KB
Loading

Readme.md

Lines changed: 63 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,67 @@
1-
# Swiftui WrappingStack
1+
# SwiftUI WrappingStack
22

3-
![Swift 5.3](https://img.shields.io/badge/Swift-5.3-FA5B2C) ![Xcode 12.5](https://img.shields.io/badge/Xcode-12-44B3F6) ![iOS 9.0](https://img.shields.io/badge/iOS-8.0-178DF6) ![iPadOS 9.0](https://img.shields.io/badge/iPadOS-8.0-178DF6) ![MacOS 10.10](https://img.shields.io/badge/MacOS-10.10-178DF6) [![Build & Test](https://github.com/diniska/swiftui-wrapping-stack/actions/workflows/test.yml/badge.svg)](https://github.com/diniska/swiftui-wrapping-stack/actions/workflows/test.yml)
3+
![Swift 5.3](https://img.shields.io/badge/Swift-5.3-FA5B2C) ![Xcode 12.5](https://img.shields.io/badge/Xcode-12.5-44B3F6) ![iOS 9.0](https://img.shields.io/badge/iOS-9.0-178DF6) ![iPadOS 9.0](https://img.shields.io/badge/iPadOS-9.0-178DF6) ![MacOS 10.10](https://img.shields.io/badge/MacOS-10.10-178DF6) [![Build & Test](https://github.com/diniska/swiftui-wrapping-stack/actions/workflows/test.yml/badge.svg)](https://github.com/diniska/swiftui-wrapping-stack/actions/workflows/test.yml)
44

55
A SwiftUI Views for wrapping HStack elements into multiple lines.
66

7-
`WrappingHStack` - provides `HStack` that supports line wrapping
7+
## List of supported views
8+
9+
* `WrappingHStack` - provides `HStack` that supports line wrapping
10+
11+
## How to use
12+
### Step 1
13+
Add a dependency using Swift Package Manager to your project: [https://github.com/diniska/swiftui-wrapping-stack](https://github.com/diniska/swiftui-wrapping-stack)
14+
15+
### Step 2
16+
Import the dependency
17+
18+
```swift
19+
import WrappingStack
20+
```
21+
22+
### Step 3
23+
Replace `HStack` with `WrappingHStack` in your view structure. It is compatible with `ForEach`.
24+
25+
```swift
26+
struct MyView: View {
27+
28+
let elements = ["Cat 🐱", "Dog 🐶", "Sun 🌞", "Moon 🌕", "Tree 🌳"]
29+
30+
var body: some View {
31+
WrappingHStack(id: \.self) { // use the same id is in the `ForEach` below
32+
ForEach(elements, id: \.self) { element in
33+
Text(element)
34+
.padding()
35+
.background(Color.gray)
36+
.cornerRadius(6)
37+
}
38+
}
39+
.frame(width: 300) // limiting the width for demo purpose. This line is not needed in real code
40+
}
41+
42+
}
43+
```
44+
45+
The result of the code above:
46+
47+
![WrappingHStack for macOS](./Docs/Resources/wrapping-hstack-macos.png)
48+
49+
50+
## Customization
51+
52+
Customize appearance using the next parameters. All the default SwiftUI modifiers can be applied as well.
53+
54+
### `WrappingHStack` parameters
55+
56+
Parameter name | Description
57+
---------------|--------------
58+
`alignment` | horizontal and vertical alignment. `.center` is used by default. Vertical alignment is applied to every row
59+
`horizontalSpacing` | horizontal spacing between elements
60+
`verticalSpacing` | vertical spacing between the lines
61+
62+
## Performance considerations
63+
64+
The code written in a way to cache the elements representing views sizes, it doesn't re-calculate the size for different views with the same id.
65+
66+
* huge numbers of elements are not recommended, although the same applies to `HStack` where `LazyHStack` is a better alternative for the long rows. If you have a large number of elements - double-check the memory and performance on a real device
67+
* it is pretty good in terms of CPU consumption as every element calculates its size only once.

Sources/WrappingStack/WrappingHStack.swift

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,21 @@ public struct WrappingHStack<Data: RandomAccessCollection, ID: Hashable, Content
3232
return result
3333
}
3434

35+
/// Creates a new WrappingHStack
36+
///
37+
/// - Parameters:
38+
/// - id: a keypath of element identifier
39+
/// - alignment: horizontal and vertical alignment. Vertical alignment is applied to every row
40+
/// - horizontalSpacing: horizontal spacing between elements
41+
/// - verticalSpacing: vertical spacing between the lines
42+
/// - create: a method that creates an array of elements
3543
public init(
3644
id: KeyPath<Data.Element, ID>,
3745
alignment: Alignment = .center,
3846
horizontalSpacing: CGFloat = 0,
3947
verticalSpacing: CGFloat = 0,
4048
@ViewBuilder content create: () -> ForEach<Data, ID, Content>
41-
){
49+
) {
4250
let forEach = create()
4351
data = forEach.data
4452
content = forEach.content
@@ -111,8 +119,24 @@ public struct WrappingHStack<Data: RandomAccessCollection, ID: Hashable, Content
111119

112120
@available(iOS 14, macOS 11, *)
113121
extension WrappingHStack where ID == Data.Element.ID, Data.Element: Identifiable {
114-
public init(@ViewBuilder content create: () -> ForEach<Data, ID, Content>) {
115-
self.init(id: \.id, content: create)
122+
/// Creates a new WrappingHStack
123+
///
124+
/// - Parameters:
125+
/// - alignment: horizontal and vertical alignment. Vertical alignment is applied to every row
126+
/// - horizontalSpacing: horizontal spacing between elements
127+
/// - verticalSpacing: vertical spacing between the lines
128+
/// - create: a method that creates an array of elements
129+
public init(
130+
alignment: Alignment = .center,
131+
horizontalSpacing: CGFloat = 0,
132+
verticalSpacing: CGFloat = 0,
133+
@ViewBuilder content create: () -> ForEach<Data, ID, Content>
134+
) {
135+
self.init(id: \.id,
136+
alignment: alignment,
137+
horizontalSpacing: horizontalSpacing,
138+
verticalSpacing: verticalSpacing,
139+
content: create)
116140
}
117141
}
118142

@@ -121,15 +145,21 @@ extension WrappingHStack where ID == Data.Element.ID, Data.Element: Identifiable
121145
@available(iOS 14, macOS 11, *)
122146
struct WrappingHStack_Previews: PreviewProvider {
123147
static var previews: some View {
124-
WrappingHStack(id: \.self, alignment: .topLeading) {
125-
ForEach(["Hello1", "world1", "Hello2", "world2", "Hello3", "world3", "Hello4", "world4 ", "Hello1"], id: \.self) { item in
126-
Text(item)
148+
WrappingHStack(
149+
id: \.self,
150+
horizontalSpacing: 8,
151+
verticalSpacing: 8
152+
) {
153+
ForEach(["Cat 🐱", "Dog 🐶", "Sun 🌞", "Moon 🌕", "Tree 🌳"], id: \.self) { element in
154+
Text(element)
127155
.padding()
128-
.background(Color(.systemGray))
129-
.cornerRadius(3)
156+
.background(Color.gray.opacity(0.1))
157+
.cornerRadius(6)
130158
}
131159
}
160+
.padding()
132161
.frame(width: 300)
162+
.background(Color.white)
133163
}
134164
}
135165

0 commit comments

Comments
 (0)