Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift add badge to navigation barButtonItem and UIButton

I am trying to display badge on my notification button, in app as displayed on AppIcon.

So far whatever i have researched is related to Obj. C, but nothing that specifically discussed way to implement that solution into Swift,

Please help to find a solution to add a custom class / code to achieve Badge on UiBarbutton and UiButton.

Researched so far:

https://github.com/Marxon13/M13BadgeView

along with MKBadge class etc.

like image 505
coolagrwal Avatar asked Jul 06 '15 00:07

coolagrwal


2 Answers

There is a more elegant solution with an extension for UIButtonItem

extension CAShapeLayer {     func drawCircleAtLocation(location: CGPoint, withRadius radius: CGFloat, andColor color: UIColor, filled: Bool) {         fillColor = filled ? color.cgColor : UIColor.white.cgColor         strokeColor = color.cgColor         let origin = CGPoint(x: location.x - radius, y: location.y - radius)         path = UIBezierPath(ovalIn: CGRect(origin: origin, size: CGSize(width: radius * 2, height: radius * 2))).cgPath     } }  private var handle: UInt8 = 0  extension UIBarButtonItem {     private var badgeLayer: CAShapeLayer? {         if let b: AnyObject = objc_getAssociatedObject(self, &handle) as AnyObject? {             return b as? CAShapeLayer         } else {             return nil         }     }      func addBadge(number: Int, withOffset offset: CGPoint = CGPoint.zero, andColor color: UIColor = UIColor.red, andFilled filled: Bool = true) {         guard let view = self.value(forKey: "view") as? UIView else { return }          badgeLayer?.removeFromSuperlayer()          // Initialize Badge         let badge = CAShapeLayer()         let radius = CGFloat(7)         let location = CGPoint(x: view.frame.width - (radius + offset.x), y: (radius + offset.y))         badge.drawCircleAtLocation(location: location, withRadius: radius, andColor: color, filled: filled)         view.layer.addSublayer(badge)          // Initialiaze Badge's label         let label = CATextLayer()         label.string = "\(number)"         label.alignmentMode = CATextLayerAlignmentMode.center         label.fontSize = 11         label.frame = CGRect(origin: CGPoint(x: location.x - 4, y: offset.y), size: CGSize(width: 8, height: 16))         label.foregroundColor = filled ? UIColor.white.cgColor : color.cgColor         label.backgroundColor = UIColor.clear.cgColor         label.contentsScale = UIScreen.main.scale         badge.addSublayer(label)          // Save Badge as UIBarButtonItem property         objc_setAssociatedObject(self, &handle, badge, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)     }      func updateBadge(number: Int) {         if let text = badgeLayer?.sublayers?.filter({ $0 is CATextLayer }).first as? CATextLayer {             text.string = "\(number)"         }     }      func removeBadge() {         badgeLayer?.removeFromSuperlayer()     } } 

This great code was created by Stefano Vettor and you can find all the details at: https://gist.github.com/freedom27/c709923b163e26405f62b799437243f4

like image 96
Julio Bailon Avatar answered Sep 22 '22 00:09

Julio Bailon


Working Solution :

Step 1: Firstly create new swift file which is a subclass to UIButton as follows:

import UIKit  class BadgeButton: UIButton {      var badgeLabel = UILabel()      var badge: String? {         didSet {             addbadgetobutton(badge: badge)         }     }      public var badgeBackgroundColor = UIColor.red {         didSet {             badgeLabel.backgroundColor = badgeBackgroundColor         }     }      public var badgeTextColor = UIColor.white {         didSet {             badgeLabel.textColor = badgeTextColor         }     }      public var badgeFont = UIFont.systemFont(ofSize: 12.0) {         didSet {             badgeLabel.font = badgeFont         }     }      public var badgeEdgeInsets: UIEdgeInsets? {         didSet {             addbadgetobutton(badge: badge)         }     }      override init(frame: CGRect) {         super.init(frame: frame)         addbadgetobutton(badge: nil)     }      func addbadgetobutton(badge: String?) {         badgeLabel.text = badge         badgeLabel.textColor = badgeTextColor         badgeLabel.backgroundColor = badgeBackgroundColor         badgeLabel.font = badgeFont         badgeLabel.sizeToFit()         badgeLabel.textAlignment = .center         let badgeSize = badgeLabel.frame.size          let height = max(18, Double(badgeSize.height) + 5.0)         let width = max(height, Double(badgeSize.width) + 10.0)          var vertical: Double?, horizontal: Double?         if let badgeInset = self.badgeEdgeInsets {             vertical = Double(badgeInset.top) - Double(badgeInset.bottom)             horizontal = Double(badgeInset.left) - Double(badgeInset.right)              let x = (Double(bounds.size.width) - 10 + horizontal!)             let y = -(Double(badgeSize.height) / 2) - 10 + vertical!             badgeLabel.frame = CGRect(x: x, y: y, width: width, height: height)         } else {             let x = self.frame.width - CGFloat((width / 2.0))             let y = CGFloat(-(height / 2.0))             badgeLabel.frame = CGRect(x: x, y: y, 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     }      required init?(coder aDecoder: NSCoder) {         super.init(coder: aDecoder)         self.addbadgetobutton(badge: nil)         fatalError("init(coder:) is not implemented")     } } 

Step 2: Create a function in your base file which u can use in each View Controller :

  func addBadge(itemvalue: String) {          let bagButton = BadgeButton()         bagButton.frame = CGRect(x: 0, y: 0, width: 44, height: 44)         bagButton.tintColor = UIColor.darkGray         bagButton.setImage(UIImage(named: "ShoppingBag")?.withRenderingMode(.alwaysTemplate), for: .normal)         bagButton.badgeEdgeInsets = UIEdgeInsets(top: 20, left: 0, bottom: 0, right: 15)         bagButton.badge = itemvalue         self.navigationItem.rightBarButtonItem = UIBarButtonItem(customView: bagButton)     } 

Step 3 : Use above function from any View Controller in this way :

self.addBadge(itemvalue: localStorage.string(forKey: "total_products_in_cart") ?? "0") 
like image 36
Shivam Tripathi Avatar answered Sep 19 '22 00:09

Shivam Tripathi