Skip to content

Commit a1bc849

Browse files
committed
Fix bug in StaticStack. Add options to add leading and trailing icons, as well as render conditionally on select
1 parent ef6d264 commit a1bc849

File tree

2 files changed

+61
-15
lines changed

2 files changed

+61
-15
lines changed

Example/PillPickerViewExample/PillPickerViewExample.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ struct ContentView: View {
3636
ExampleBuilder(selectedItems: $selectedGenres, content: {
3737
PillPickerView(items: genres, selectedPills: $selectedGenres)
3838
.pillStackStyle(.wrap)
39+
.pillLeadingIcon(Image(systemName: "popcorn"))
40+
.pillTrailingIcon(Image(systemName: "checkmark"))
41+
.pillTrailingOnlySelected(true)
3942
})
4043
.tag(0)
4144
.navigationTitle("Wrapping pills")
@@ -45,6 +48,9 @@ struct ContentView: View {
4548
ExampleBuilder(selectedItems: $selectedGenres, content: {
4649
PillPickerView(items: genres, selectedPills: $selectedGenres)
4750
.pillStackStyle(.noWrap)
51+
.pillLeadingIcon(Image(systemName: "popcorn"))
52+
.pillTrailingIcon(Image(systemName: "checkmark"))
53+
.pillTrailingOnlySelected(true)
4854
})
4955
.tag(1)
5056
.navigationTitle("Static pills")

Sources/PillPickerView.swift

Lines changed: 55 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,19 @@ public struct PillOptions {
6666
/// Spacing applied horizontally between pills
6767
public var horizontalSpacing: CGFloat = 2
6868

69-
/// Icon displayed in the pill when selected
70-
public var selectedIcon: Image = Image(systemName: "xmark")
69+
/// Trailing icon displayed inside the pills
70+
public var trailingIcon: Image? = nil
71+
72+
/// Leading icon displayed inside the pills
73+
public var leadingIcon: Image? = nil
74+
75+
/// Whether leading icon should only be displayed if
76+
/// the element is selected or not
77+
public var leadingOnlyWhenSelected: Bool = false
78+
79+
/// Whether trailing icon should only be displayed if
80+
/// the element is selected or not
81+
public var trailingOnlyWhenSelected: Bool = false
7182
}
7283

7384
// MARK: - Main view
@@ -221,9 +232,27 @@ public extension PillPickerView {
221232
return view
222233
}
223234

224-
func pillSelectedIcon(_ value: Image) -> PillPickerView {
235+
func pillLeadingIcon(_ value: Image) -> PillPickerView {
236+
var view = self
237+
view.options.leadingIcon = value
238+
return view
239+
}
240+
241+
func pillTrailingIcon(_ value: Image) -> PillPickerView {
242+
var view = self
243+
view.options.trailingIcon = value
244+
return view
245+
}
246+
247+
func pillTrailingOnlySelected(_ value: Bool) -> PillPickerView {
225248
var view = self
226-
view.options.selectedIcon = value
249+
view.options.trailingOnlyWhenSelected = value
250+
return view
251+
}
252+
253+
func pillLeadingOnlySelected(_ value: Bool) -> PillPickerView {
254+
var view = self
255+
view.options.leadingOnlyWhenSelected = value
227256
return view
228257
}
229258

@@ -252,23 +281,20 @@ struct PillView<T: Pill>: View {
252281
withAnimation(options.animation) {
253282
if !isItemSelected() {
254283
selectedPills.append(item)
284+
} else {
285+
selectedPills.removeAll(where: { $0 == item })
255286
}
256287
}
257288
}, label: {
258289
HStack {
290+
if !options.leadingOnlyWhenSelected || isItemSelected() {
291+
leadingIcon
292+
}
259293
Text(item.title)
260294
.font(options.font)
261295
.foregroundColor(pillForegroundColor)
262-
if isItemSelected() {
263-
options.selectedIcon
264-
.font(options.font)
265-
.foregroundColor(pillForegroundColor)
266-
.padding(.leading, 5)
267-
.onTapGesture {
268-
withAnimation(options.animation) {
269-
selectedPills.removeAll(where: { $0 == item })
270-
}
271-
}
296+
if !options.trailingOnlyWhenSelected || isItemSelected() {
297+
trailingIcon
272298
}
273299
}
274300
.padding(options.padding)
@@ -286,6 +312,20 @@ struct PillView<T: Pill>: View {
286312
.padding(.vertical, 2.5)
287313
}
288314

315+
var leadingIcon: some View {
316+
options.leadingIcon
317+
.font(options.font)
318+
.foregroundColor(pillForegroundColor)
319+
.padding(.leading, 5)
320+
}
321+
322+
var trailingIcon: some View {
323+
options.trailingIcon
324+
.font(options.font)
325+
.foregroundColor(pillForegroundColor)
326+
.padding(.leading, 5)
327+
}
328+
289329
// MARK: - Helper Functions
290330

291331
/// Checks if @Binding collection contains
@@ -371,7 +411,7 @@ struct StaticStack<T, V>: View where T: Pill, V: View {
371411
let availableWidth = geometry.size.width
372412
let itemWidth: CGFloat = 100
373413

374-
chunkSize = max(Int(availableWidth / (itemWidth + options.horizontalSpacing)), 1)
414+
chunkSize = max(Int(availableWidth / (itemWidth + options.minWidth)), 1)
375415
}
376416

377417
// MARK: - Height Calculation

0 commit comments

Comments
 (0)