Skip to content

Commit 3dd1972

Browse files
authored
Merge pull request #1 from adisve/ui/wrapping
UI/wrapping
2 parents a02a5c9 + 8a805a1 commit 3dd1972

File tree

11 files changed

+351
-76
lines changed

11 files changed

+351
-76
lines changed

Assets/Header.png

-3.22 KB
Loading

Assets/Logo.png

725 Bytes
Loading

Assets/Showroom_1.png

32 KB
Loading

Assets/Showroom_2.png

81.4 KB
Loading

Example/PillPickerViewExample/Assets.xcassets/AccentColor.colorset/Contents.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
{
22
"colors" : [
33
{
4+
"color" : {
5+
"color-space" : "srgb",
6+
"components" : {
7+
"alpha" : "1.000",
8+
"blue" : "0x6F",
9+
"green" : "0x52",
10+
"red" : "0xEA"
11+
}
12+
},
413
"idiom" : "universal"
514
}
615
],

Example/PillPickerViewExample/Assets.xcassets/AppIcon.appiconset/Contents.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"images" : [
33
{
4-
"filename" : "PillPickerViewLogo.png",
4+
"filename" : "Logo.png",
55
"idiom" : "universal",
66
"platform" : "ios",
77
"size" : "1024x1024"
23.5 KB
Loading
Binary file not shown.

Example/PillPickerViewExample/PillPickerViewExample.swift

Lines changed: 109 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -21,54 +21,125 @@ struct PillPickerViewExample: App {
2121

2222
struct ContentView: View {
2323

24-
/// Sample model conforming to the `Pill` protocol.
25-
/// An element must have a `title` attribute.
26-
struct ColorPill: Pill {
27-
let title: String
28-
let color: Color
29-
}
30-
3124
/// Required collection of items confirming to `Pill`
3225
/// which will be used for tracking which objects
3326
/// are selected
34-
@State private var selectedColors: [ColorPill] = []
35-
36-
/// Collection of items conforming to `Pill`
37-
let colorPills: [ColorPill] = [
38-
ColorPill(title: "Red", color: .red),
39-
ColorPill(title: "Green", color: .green),
40-
ColorPill(title: "Blue", color: .blue),
41-
ColorPill(title: "Yellow", color: .yellow),
42-
ColorPill(title: "Orange", color: .orange),
43-
ColorPill(title: "Purple", color: .purple),
44-
ColorPill(title: "Pink", color: .pink),
45-
]
27+
@State private var selectedGenres: [Genre] = []
4628

4729
var body: some View {
4830
NavigationView {
49-
VStack(alignment: .leading, spacing: 40) {
50-
Text("Select Your Favorite Colors")
31+
VStack {
32+
TabView {
33+
34+
/// Example view where pills wrap to new line and only occupy
35+
/// necessary space
36+
ExampleBuilder(selectedItems: $selectedGenres, content: {
37+
PillPickerView(items: genres, selectedPills: $selectedGenres)
38+
.pillStackStyle(.wrap)
39+
})
40+
.tag(0)
41+
.navigationTitle("Wrapping pills")
42+
43+
/// Example view where pills do not wrap to new line and occupy
44+
/// set amount of space horizontally and vertically
45+
ExampleBuilder(selectedItems: $selectedGenres, content: {
46+
PillPickerView(items: genres, selectedPills: $selectedGenres)
47+
.pillStackStyle(.noWrap)
48+
})
49+
.tag(1)
50+
.navigationTitle("Static pills")
51+
}
52+
.tabViewStyle(.page)
53+
.tint(.accentColor)
54+
}
55+
.toolbar(content: {
56+
ToolbarItem(placement: .navigationBarTrailing, content: {
57+
Button(action: {
58+
withAnimation {
59+
selectedGenres.removeAll()
60+
}
61+
}, label: {
62+
Text("Clear All")
63+
})
64+
})
65+
})
66+
}
67+
}
68+
}
69+
70+
struct ExampleBuilder<T, V>: View where T: Pill, V: View {
71+
72+
typealias ContentGenerator = () -> V
73+
74+
@Binding var selectedItems: [T]
75+
76+
var content: ContentGenerator
77+
78+
var body: some View {
79+
ScrollView (showsIndicators: false) {
80+
HStack {
81+
Text("Select Your Favorite Genres")
5182
.font(.system(size: 26, weight: .semibold, design: .rounded))
52-
53-
/// PillPickerView usage example
54-
PillPickerView(items: colorPills, selectedPills: $selectedColors)
55-
56-
Text("Selected Colors:")
57-
.font(.system(size: 20, weight: .semibold, design: .rounded))
58-
59-
HStack(spacing: 10) {
60-
ForEach(selectedColors, id: \.self) { colorPill in
61-
RoundedRectangle(cornerRadius: 40)
62-
.foregroundColor(colorPill.color)
63-
.frame(width: 40, height: 40)
83+
Spacer()
84+
}
85+
.padding(.vertical, 30)
86+
87+
/// PillPickerView usage example
88+
content()
89+
90+
Text("Selected Genres:")
91+
.font(.system(size: 20, weight: .semibold, design: .rounded))
92+
.padding(.top, 30)
93+
94+
VStack(spacing: 10) {
95+
ForEach(selectedItems, id: \.self) { item in
96+
HStack {
97+
Text(item.title)
98+
.font(.system(size: 16, weight: .semibold, design: .rounded))
99+
.foregroundColor(.white)
64100
}
101+
.padding()
102+
.frame(maxWidth: .infinity)
103+
.background(
104+
RoundedRectangle(cornerRadius: 20)
105+
.foregroundColor(.accentColor)
106+
)
65107
}
66-
67-
Spacer()
68108
}
69-
.padding()
70-
.padding(.top, 15)
71-
.navigationTitle("PillPickerView")
109+
.padding(.bottom, 60)
110+
111+
Spacer()
72112
}
113+
.padding(.horizontal, 15)
73114
}
74115
}
116+
117+
/// Sample model conforming to the `Pill` protocol.
118+
/// An element must have a `title` attribute.
119+
struct Genre: Pill {
120+
let title: String
121+
}
122+
123+
/// Collection of items conforming to `Pill`
124+
let genres: [Genre] = [
125+
Genre(title: "Action"),
126+
Genre(title: "Adventure"),
127+
Genre(title: "Comedy"),
128+
Genre(title: "Drama"),
129+
Genre(title: "Fantasy"),
130+
Genre(title: "Horror"),
131+
Genre(title: "Mystery"),
132+
Genre(title: "Romance"),
133+
Genre(title: "Sci-Fi"),
134+
Genre(title: "Thriller"),
135+
Genre(title: "Western"),
136+
Genre(title: "Animation"),
137+
Genre(title: "Documentary"),
138+
Genre(title: "Historical"),
139+
Genre(title: "Musical"),
140+
Genre(title: "War"),
141+
Genre(title: "Crime"),
142+
Genre(title: "Family"),
143+
Genre(title: "Sports"),
144+
Genre(title: "Biography")
145+
]

README.md

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,20 @@ A SwiftUI library to present a Pill Picker view
2121

2222
## How it looks
2323

24+
<div style="display:flex; justify-content: center;">
25+
<div>
26+
<h4>Static placement</h4>
27+
<img src="Assets/Showroom_1.png" alt="PillPickerView example 1" style="width: 200px;margin-right:50px;"/>
28+
</div>
29+
<div>
30+
<h4>Flowing placement</h4>
31+
<img src="Assets/Showroom_2.png" alt="PillPickerView example 2" style="width: 200px;"/>
32+
</div>
33+
</div>
34+
35+
<br>
36+
37+
Demo:
2438
https://github.com/adisve/PillPickerView/assets/96535657/4f052e75-36f1-4f59-9664-0a187b07de28
2539

2640
<br>
@@ -124,8 +138,12 @@ In the example above, replace YourPillType with your custom pill type and yourIt
124138

125139
PillPickerView offers a range of customization options to tailor the appearance of the pills to your app's design. You can customize the font, colors, animation, size, and other visual aspects of the pills by using the available modifier functions.
126140

141+
The PillPickerView includes a wrapping mechanism that automatically adjusts the layout of pills to fit within the available space. If the pills exceed the horizontal width of the container, the view wraps the excess pills to a new line. This makes it easy to present a large number of pills without worrying about truncation.
142+
127143
You can customize the appearance of the pills by chaining the available modifier functions on the PillPickerView. For example:
128144

145+
<br>
146+
129147
```swift
130148
PillPickerView(
131149
items: yourItemList,
@@ -138,6 +156,22 @@ PillPickerView(
138156

139157
<br>
140158

159+
To switch between the underlying stack style for the content. Choosing `.noWrap` will invariably cause any text inside the pills to be truncated depending on length, as it will automatically be fitted inside the view and not wrap to a new line. Choosing `.wrap` will let the pills be dynamically placed an move in the PillPickerView.
160+
161+
```swift
162+
.pillStackStyle(.noWrap) // Prevents pills from wrapping to a new line and being dynamic
163+
.pillStackStyle(.wrap) // Default value. Allows pills to move in container
164+
```
165+
166+
<br>
167+
168+
To modify the vertical or horizontal spacing in the PillPickerView
169+
170+
```swift
171+
.pillViewVerticalSpacing(10)
172+
.pillViewHorizontalSpacing(5)
173+
```
174+
141175
To change the font of the pills
142176

143177
```swift
@@ -146,6 +180,24 @@ To change the font of the pills
146180

147181
<br>
148182

183+
You can of course chain things together to get a good layout based on your circumstances and requirements.
184+
185+
```swift
186+
.pillFont(.title3)
187+
.pillViewHorizontalSpacing(30)
188+
```
189+
190+
<br>
191+
192+
To change the icon used by each pill when it is 'selected'.
193+
I advise you to choose something that indicates that the pill will no longer be selected if this icon is pressed, as this is the intended behavior.
194+
195+
```swift
196+
.pillSelectedIcon(Image(systemName: "xmark"))
197+
```
198+
199+
<br>
200+
149201
To change the background color of a not selected and selected pill, respectively
150202

151203
```swift
@@ -195,9 +247,3 @@ Padding can also be applied
195247
```swift
196248
.pillPadding(10)
197249
```
198-
199-
<br>
200-
201-
## Note:
202-
203-
The PillPickerView includes a wrapping mechanism that automatically adjusts the layout of pills to fit within the available space. If the pills exceed the horizontal width of the container, the view wraps the excess pills to a new line. This makes it easy to present a large number of pills without worrying about truncation.

0 commit comments

Comments
 (0)