J'essaie d'afficher un badge sur mon bouton de notification, dans l'application telle qu'elle est affichée sur AppIcon.
Jusqu'à présent, tout ce que j'ai étudié est lié à Obj. C, mais rien qui ait spécifiquement discuté de la manière de mettre en œuvre cette solution dans Swift,
Aidez-nous à trouver une solution pour ajouter une classe/un code personnalisé permettant d’obtenir un badge sur UiBarbutton et UiButton.
Cherché jusqu'ici:
https://github.com/Marxon13/M13BadgeView
avec classe MKBadge etc.
Il existe une solution plus élégante avec une extension pour 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 = kCAAlignmentCenter
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()
}
}
Ce code génial a été créé par Stefano Vettor et vous pouvez trouver tous les détails sur: https://Gist.github.com/freedom27/c709923b163e26405f62b799437243f4
Solution de travail:
Étape 1: Créez d’abord un nouveau fichier Swift qui est une sous-classe de UIButton, comme suit:
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")
}
}
Étape 2: Créez une fonction dans votre fichier de base que vous pourrez utiliser dans chaque contrôleur de vue:
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)
}
Étape 3: Utilisez la fonction ci-dessus à partir de n’importe quel contrôleur de vue de cette manière:
self.addBadge(itemvalue: localStorage.string(forKey: "total_products_in_cart") ?? "0")
en utilisant M13BadgeView .. utilisez ce code
(J'utilise fontawesome.Swift pour les boutons :: https://github.com/thii/FontAwesome.Swift )
let rightButton = UIButton(frame: CGRect(x:0,y:0,width:30,height:30))
rightButton.titleLabel?.font = UIFont.fontAwesome(ofSize: 22)
rightButton.setTitle(String.fontAwesomeIcon(name: .shoppingBasket), for: .normal)
let rightButtonItem : UIBarButtonItem = UIBarButtonItem(customView: rightButton)
let badgeView = M13BadgeView()
badgeView.text = "1"
badgeView.textColor = UIColor.white
badgeView.badgeBackgroundColor = UIColor.red
badgeView.borderWidth = 1.0
badgeView.borderColor = UIColor.white
badgeView.horizontalAlignment = M13BadgeViewHorizontalAlignmentLeft
badgeView.verticalAlignment = M13BadgeViewVerticalAlignmentTop
badgeView.hidesWhenZero = true
rightButton.addSubview(badgeView)
self.navigationItem.rightBarButtonItem = rightButtonItem
J'ai eu la même tâche. Je ne voulais pas utiliser de bibliothèques tierces. Tout d’abord, j’ai essayé la solution de Stefano et c’est génial, mais j’ai décidé de mettre en œuvre ma propre façon de le résoudre.
À mon humble avis, quelques étapes simples sont décrites brièvement ci-dessous:
UIView
dans le fichier .xib
et placez les éléments nécessaires tels que UILabel
ou UIImageView
instance en fonction de vos exigences de conception . La dernière action que j'ai faite dans cette étape consiste à placer un bouton invisible dans la hiérarchie du haut de la vue.
YourCustomView.Swift
et liez tous les @IBOutlets
de xib
au fichier en cours dans votre implémentation de classe d'affichage personnalisée.YourCustomView
qui chargera la vue personnalisée à partir de xib et la retournera en tant qu’instance YourCustomView
.Mon résultat est ..
P.S. Si vous devez implémenter @IBActions
, je vous recommande de lier votre vue personnalisée à votre contrôleur de vue personnalisé via le modèle de délégué.
Bonne réponse @Julio Bailon ( https://stackoverflow.com/a/45948819/1898973 )!
Voici le site de l'auteur avec l'explication complète: http://www.stefanovettor.com/2016/04/30/adding-badge-uibarbuttonitem/ .
Il semble ne pas fonctionner sur iOS 11, peut-être parce que le script tente d'accéder à la propriété "view" de UIBarButtonItem. Je l'ai fait fonctionner:
En créant une UIButton
puis en créant la UIBarButtonItem
en utilisant la UIButton
en tant que customView:
navigationItem.rightBarButtonItem = UIBarButtonItem.init(
customView: shoppingCartButton)
En remplaçant la ligne dans l'extension UIBarButtonItem
:
guard let view = self.value(forKey: "view") as? UIView else { return }
avec ce qui suit:
guard let view = self.customView else { return }
Cela me semble élégant et, mieux encore, cela a fonctionné!