I use the following code to update my right BarButtonItem, but I am currently working with local data to accomplish this. With an API and database connection, the update functionality will be a little bit different, since it will probably have to remember each customer's cart total until emptied.
// My custom badge button
class BadgeButton: UIButton {
var badgeLabel = UILabel()
var badge: String? {
didSet {
addBadgeToButton(badge: badge)
}
}
public var badgeEdgeInsets: UIEdgeInsets? {
didSet {
addBadgeToButton(badge: badge)
}
}
override init(frame: CGRect) {
super.init(frame: frame)
addBadgeToButton(badge: nil)
}
func addBadgeToButton(badge: String?) {
guard let badgeTotal = badge else { return }
badgeLabel.attributedText = NSMutableAttributedString().appendWith(color: .white, weight: .regular, ofSize: 15, badgeTotal)
badgeLabel.backgroundColor =.red
badgeLabel.sizeToFit()
badgeLabel.textAlignment = .center
let badgeSize = badgeLabel.frame.size
let height = max(18, Double(badgeSize.height) + 5)
let width = max(height, Double(badgeSize.width) + 10)
var vertical: Double?, horizontal: Double?
if let badgeInset = self.badgeEdgeInsets {
vertical = Double(badgeInset.top) - Double(badgeInset.bottom)
horizontal = Double(badgeInset.left) - Double(badgeInset.right)
badgeLabel.frame = CGRect(x: (Double(bounds.size.width) - 10 + horizontal!), y: -(Double(badgeSize.height) / 2) - 10 + vertical!, width: width, height: height)
} else {
badgeLabel.frame = CGRect(x: self.frame.width - CGFloat((width / 2)), y: CGFloat(-(height / 2)), width: CGFloat(width), height: CGFloat(height))
}
badgeLabel.layer.cornerRadius = badgeLabel.frame.height / 2
badgeLabel.layer.masksToBounds = true
addSubview(badgeLabel)
badgeLabel.isHidden = badge != nil ? false : true
if badgeLabel.text == "0" {
badgeLabel.isHidden = true
}
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.addBadgeToButton(badge: nil)
fatalError()
}
}
// Create the navigation bar item
fileprivate func createChatIcon(itemvalue: String) {
chatButton.frame = CGRect(x: 0, y: 0, width: 44, height: 44)
chatButton.badgeEdgeInsets = UIEdgeInsets(top: 20, left: 0, bottom: 0, right: 15)
chatButton.badge = itemvalue
chatButton.tintColor = .white
chatButton.setImage(UIImage(named: "chat")?.withRenderingMode(.alwaysTemplate), for: .normal)
chatButton.addTarget(self, action: #selector(handleLaunchChatOverview), for: .touchUpInside)
self.navigationItem.rightBarButtonItem = UIBarButtonItem(customView: chatButton)
}
// Itemvalue can be set to 0 if you want. I am working on a chat functionality, so I need to load the total unread messages from the server when completed. This will be my initial value :-)
_ = createChatIcon(itemvalue: "\(userViewModel.first?.unreadMessages ?? 0)"
var itemTotal = 0
@objc fileprivate func handleAddItem() {
itemTotal += 1
refreshTotal()
}
@objc fileprivate func handleRemoveItem() {
itemTotal -= 1
refreshTotal()
}
fileprivate func refreshTotal() {
chatButton.badge = "\(itemTotal)"
}