Skip to content

Commit c81e6ca

Browse files
committed
feat: ability to handle badges. Refs onl1ner#21
1 parent 995e6bc commit c81e6ca

File tree

6 files changed

+64
-18
lines changed

6 files changed

+64
-18
lines changed

Example/Example/ContentView.swift

+31-3
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,23 @@ struct ContentView: View {
5050

5151
@State private var selection: Item = .first
5252
@State private var visibility: TabBarVisibility = .visible
53+
@State private var badgeNumberAtThird = 0
54+
55+
private func badgeNumber(for tabItem: Item) -> Int? {
56+
switch tabItem {
57+
case Item.third:
58+
return badgeNumberAtThird
59+
default:
60+
return nil
61+
}
62+
}
5363

5464
var body: some View {
55-
TabBar(selection: $selection, visibility: $visibility) {
65+
TabBar(
66+
selection: $selection,
67+
visibility: $visibility,
68+
badgeNumberForTabItem: badgeNumber(for:)
69+
) {
5670
Button {
5771
withAnimation {
5872
visibility.toggle()
@@ -65,8 +79,22 @@ struct ContentView: View {
6579
Text("Second")
6680
.tabItem(for: Item.second)
6781

68-
Text("Third")
69-
.tabItem(for: Item.third)
82+
VStack(spacing: 40) {
83+
Text("Third")
84+
85+
Button {
86+
badgeNumberAtThird += 1
87+
} label: {
88+
Text("Increase Badge Number")
89+
}
90+
91+
Button {
92+
badgeNumberAtThird = 0
93+
} label: {
94+
Text("Reset Badge Number")
95+
}
96+
}
97+
.tabItem(for: Item.third)
7098
}
7199
.tabBar(style: CustomTabBarStyle())
72100
.tabItem(style: CustomTabItemStyle())

Example/Example/Styles/TabItem/CustomTabItemStyle.swift

+13-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import TabBar
2626

2727
struct CustomTabItemStyle: TabItemStyle {
2828

29-
public func tabItem(icon: String, title: String, isSelected: Bool) -> some View {
29+
public func tabItem(icon: String, title: String, isSelected: Bool, badgeNumber: Int?) -> some View {
3030
ZStack {
3131
if isSelected {
3232
Circle()
@@ -37,6 +37,18 @@ struct CustomTabItemStyle: TabItemStyle {
3737
Image(systemName: icon)
3838
.foregroundColor(isSelected ? .white : Color("color.tab.item.foreground"))
3939
.frame(width: 32.0, height: 32.0)
40+
41+
if let badgeNumber = badgeNumber, badgeNumber > 0 {
42+
Text("\(badgeNumber < 100 ? String(badgeNumber) : "99+")")
43+
.font(.callout)
44+
.foregroundColor(.white)
45+
.padding(.horizontal, 8)
46+
.background(
47+
Capsule()
48+
.foregroundColor(.red)
49+
)
50+
.offset(x: 26, y: -10)
51+
}
4052
}
4153
.padding(.vertical, 8.0)
4254
}

Sources/TabBar/Common/Styles/TabItem/AnyTabItemStyle.swift

+4-4
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,13 @@ import SwiftUI
3131
to represent any item style.
3232
*/
3333
public struct AnyTabItemStyle: TabItemStyle {
34-
private let _makeTabItem: (String, String, String, Bool) -> AnyView
34+
private let _makeTabItem: (String, String, String, Bool, Int?) -> AnyView
3535

3636
public init<TabItem: TabItemStyle>(itemStyle: TabItem) {
37-
self._makeTabItem = itemStyle.tabItemErased(icon:selectedIcon:title:isSelected:)
37+
self._makeTabItem = itemStyle.tabItemErased(icon:selectedIcon:title:isSelected:badgeNumber:)
3838
}
3939

40-
public func tabItem(icon: String, selectedIcon: String, title: String, isSelected: Bool) -> some View {
41-
return self._makeTabItem(icon, selectedIcon, title, isSelected)
40+
public func tabItem(icon: String, selectedIcon: String, title: String, isSelected: Bool, badgeNumber: Int?) -> some View {
41+
return self._makeTabItem(icon, selectedIcon, title, isSelected, badgeNumber)
4242
}
4343
}

Sources/TabBar/Common/Styles/TabItem/DefaultTabItem.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import SwiftUI
3030
items of `UITabBar` and used in `TabBar` by default.
3131
*/
3232
public struct DefaultTabItemStyle: TabItemStyle {
33-
public func tabItem(icon: String, selectedIcon: String, title: String, isSelected: Bool) -> some View {
33+
public func tabItem(icon: String, selectedIcon: String, title: String, isSelected: Bool, badgeNumber: Int?) -> some View {
3434
VStack(spacing: 5.0) {
3535
Image(systemName: icon)
3636
.renderingMode(.template)

Sources/TabBar/Common/Styles/TabItem/TabItemStyle.swift

+8-8
Original file line numberDiff line numberDiff line change
@@ -33,20 +33,20 @@ import SwiftUI
3333
public protocol TabItemStyle {
3434
associatedtype Content : View
3535

36-
func tabItem(icon: String, title: String, isSelected: Bool) -> Content
37-
func tabItem(icon: String, selectedIcon: String, title: String, isSelected: Bool) -> Content
36+
func tabItem(icon: String, title: String, isSelected: Bool, badgeNumber: Int?) -> Content
37+
func tabItem(icon: String, selectedIcon: String, title: String, isSelected: Bool, badgeNumber: Int?) -> Content
3838
}
3939

4040
extension TabItemStyle {
41-
public func tabItem(icon: String, title: String, isSelected: Bool) -> Content {
42-
return self.tabItem(icon: icon, selectedIcon: icon, title: title, isSelected: isSelected)
41+
public func tabItem(icon: String, title: String, isSelected: Bool, badgeNumber: Int?) -> Content {
42+
return self.tabItem(icon: icon, selectedIcon: icon, title: title, isSelected: isSelected, badgeNumber: badgeNumber)
4343
}
4444

45-
public func tabItem(icon: String, selectedIcon: String, title: String, isSelected: Bool) -> Content {
46-
return self.tabItem(icon: icon, title: title, isSelected: isSelected)
45+
public func tabItem(icon: String, selectedIcon: String, title: String, isSelected: Bool, badgeNumber: Int?) -> Content {
46+
return self.tabItem(icon: icon, title: title, isSelected: isSelected, badgeNumber: badgeNumber)
4747
}
4848

49-
func tabItemErased(icon: String, selectedIcon: String, title: String, isSelected: Bool) -> AnyView {
50-
return .init(self.tabItem(icon: icon, selectedIcon: selectedIcon, title: title, isSelected: isSelected))
49+
func tabItemErased(icon: String, selectedIcon: String, title: String, isSelected: Bool, badgeNumber: Int?) -> AnyView {
50+
return .init(self.tabItem(icon: icon, selectedIcon: selectedIcon, title: title, isSelected: isSelected, badgeNumber: badgeNumber))
5151
}
5252
}

Sources/TabBar/View/TabBar.swift

+7-1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ public struct TabBar<TabItem: Tabbable, Content: View>: View {
5252
private var tabItemStyle : AnyTabItemStyle
5353
private var tabBarStyle : AnyTabBarStyle
5454

55+
private var badgeNumberForTabItem: (TabItem) -> Int?
56+
5557
@State private var items: [TabItem]
5658

5759
@Binding private var visibility: TabBarVisibility
@@ -67,11 +69,14 @@ public struct TabBar<TabItem: Tabbable, Content: View>: View {
6769
public init(
6870
selection: Binding<TabItem>,
6971
visibility: Binding<TabBarVisibility> = .constant(.visible),
72+
badgeNumberForTabItem: @escaping (TabItem) -> Int? = { _ in nil },
7073
@ViewBuilder content: () -> Content
7174
) {
7275
self.tabItemStyle = .init(itemStyle: DefaultTabItemStyle())
7376
self.tabBarStyle = .init(barStyle: DefaultTabBarStyle())
7477

78+
self.badgeNumberForTabItem = badgeNumberForTabItem
79+
7580
self.selectedItem = .init(selection: selection)
7681
self.content = content()
7782

@@ -86,7 +91,8 @@ public struct TabBar<TabItem: Tabbable, Content: View>: View {
8691
icon: item.icon,
8792
selectedIcon: item.selectedIcon,
8893
title: item.title,
89-
isSelected: self.selectedItem.selection == item
94+
isSelected: self.selectedItem.selection == item,
95+
badgeNumber: badgeNumberForTabItem(item)
9096
)
9197
.onTapGesture {
9298
self.selectedItem.selection = item

0 commit comments

Comments
 (0)