我正在尝试在AppIcon上显示的app中的通知按钮上显示徽章。
到目前为止,无论我研究过什么都与Obj有关。 C,但没有具体讨论将该解决方案实现到Swift中的方法,
请帮助找到添加自定义类/代码的解决方案,以在UiBarbutton和UiButton上实现Badge。
目前已研究过:
https://github.com/Marxon13/M13BadgeView
以及MKBadge类等。
答案 0 :(得分:12)
有一个更优雅的解决方案,扩展了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()
}
}
这个伟大的代码是由Stefano Vettor创建的,您可以在以下位置找到所有详细信息: https://gist.github.com/freedom27/c709923b163e26405f62b799437243f4
答案 1 :(得分:8)
工作解决方案:
步骤1: 首先创建新的swift文件,它是UIButton的子类,如下所示:
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")
}
}
步骤2: 在基本文件中创建一个函数,您可以在每个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)
}
第3步: 以这种方式在任何View Controller中使用上述功能:
self.addBadge(itemvalue: localStorage.string(forKey: "total_products_in_cart") ?? "0")
答案 2 :(得分:8)
首先创建标签,然后单击右键。在右栏按钮上添加子视图,这将是徽章计数。最后添加导航右栏按钮。
SWIFT 5
let badgeCount = UILabel(frame: CGRect(x: 22, y: -05, width: 20, height: 20))
badgeCount.layer.borderColor = UIColor.clear.cgColor
badgeCount.layer.borderWidth = 2
badgeCount.layer.cornerRadius = badgeCount.bounds.size.height / 2
badgeCount.textAlignment = .center
badgeCount.layer.masksToBounds = true
badgeCount.textColor = .white
badgeCount.font = badgeCount.font.withSize(12)
badgeCount.backgroundColor = .red
badgeCount.text = "4"
let rightBarButton = UIButton(frame: CGRect(x: 0, y: 0, width: 35, height: 35))
rightBarButton.setBackgroundImage(UIImage(named: "NotificationBell"), for: .normal)
rightBarButton.addTarget(self, action: #selector(self.onBtnNotification), for: .touchUpInside)
rightBarButton.addSubview(badgeCount)
let rightBarButtomItem = UIBarButtonItem(customView: rightBarButton)
navigationItem.rightBarButtonItem = rightBarButtomItem
答案 3 :(得分:2)
使用M13BadgeView ..使用此代码
(我使用fontawesome.swift for buttons :: 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
答案 4 :(得分:1)
很好的答案@Julio Bailon(https://stackoverflow.com/a/45948819/1898973)!
以下是作者网站的完整说明:http://www.stefanovettor.com/2016/04/30/adding-badge-uibarbuttonitem/。
似乎没有在iOS 11上运行,可能是因为脚本试图访问"视图" UIBarButtonItem的属性。我做到了:
创建UIButton
,然后使用UIBarButtonItem
作为自定义视图创建UIButton
:
navigationItem.rightBarButtonItem = UIBarButtonItem.init(
customView: shoppingCartButton)
替换UIBarButtonItem
扩展名中的行:
guard let view = self.value(forKey: "view") as? UIView else { return }
以下内容:
guard let view = self.customView else { return }
对我而言似乎很优雅,最重要的是,它有效!
答案 5 :(得分:1)
我有同样的任务。我不想使用第三方库。首先,我尝试了Stefano's solution,但这很棒,但是我决定采用自己的方式来解决它。
以我的拙见,下面简单介绍了一些简单的步骤:
我在此步骤中所做的最后一个操作是将不可见按钮放在视图层次结构的顶部。
YourCustomView.swift
并将@IBOutlets
中的所有xib
链接到自定义视图类实现中的当前文件。YourCustomView
类中实现类函数,该类函数将从xib加载自定义视图并将其作为YourCustomView
实例返回。我的结果是..
PS 。如果您需要实现@IBActions
,建议通过委托模式链接自定义视图和自定义视图控制器。
答案 6 :(得分:1)
您可以针对UILabel
将以下约束设置为UIButton
对齐UILabel
的顶部并尾随UIButton
当您需要显示徽章时,请将文本设置为UILabel
,而当您不想显示徽章时,请将空字符串设置为UILabel
答案 7 :(得分:1)
从 Julio 扩展名的答案不起作用。
从iOS 11开始,此代码将不起作用,因为以下代码行将不会强制转换UIView。此外,它还算作私有API,似乎不会通过AppStore审查。
guard let view = self.value(forKey: "view") as? UIView else { return }
Thread on Apple Developer Forum
此代码段总是绘制圆形的第二件事,因此它不能容纳大于9的数字。
答案 8 :(得分:0)
对于 BarButtonItem :在项目中拖放 UIBarButtonItem + Badge.h 和 UIBarButtonItem + Badge.m 类。
为此代码写一组徽章:
self.navigationItem.rightBarButtonItem.badgeValue = "2"
self.navigationItem.rightBarButtonItem.badgeBGColor = UIColor.black
对于 UIButtton :在项目中拖放 UIButton + Badge.h 和 UIButton + Badge.m 类。
self.notificationBtn.badgeValue = "2"
self.notificationBtn.badgeBGColor = UIColor.black
答案 9 :(得分:0)
答案 10 :(得分:0)
如果您只想添加不带数字的红点,则轻松而清晰的解决方案;
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 setBadge(offset: CGPoint = .zero, color: UIColor = .red, filled: Bool = true, fontSize: CGFloat = 11) {
badgeLayer?.removeFromSuperlayer()
guard let view = self.value(forKey: "view") as? UIView else {
return
}
var font = UIFont.systemFont(ofSize: fontSize)
if #available(iOS 9.0, *) {
font = UIFont.monospacedDigitSystemFont(ofSize: fontSize, weight: .regular)
}
//Size of the dot
let badgeSize = UILabel(frame: CGRect(x: 22, y: -05, width: 10, height: 10))
// initialize Badge
let badge = CAShapeLayer()
let height = badgeSize.height
let width = badgeSize.width
// x position is offset from right-hand side
let x = view.frame.width + offset.x - 17
let y = view.frame.height + offset.y - 34
let badgeFrame = CGRect(origin: CGPoint(x: x, y: y), size: CGSize(width: width, height: height))
badge.drawRoundedRect(rect: badgeFrame, andColor: color, filled: filled)
view.layer.addSublayer(badge)
// initialiaze Badge's label
let label = CATextLayer()
label.alignmentMode = .center
label.font = font
label.fontSize = font.pointSize
label.frame = badgeFrame
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)
// bring layer to front
badge.zPosition = 1_000
}
private func removeBadge() {
badgeLayer?.removeFromSuperlayer()
}
}
// MARK: - Utilities
extension CAShapeLayer {
func drawRoundedRect(rect: CGRect, andColor color: UIColor, filled: Bool) {
fillColor = filled ? color.cgColor : UIColor.white.cgColor
strokeColor = color.cgColor
path = UIBezierPath(roundedRect: rect, cornerRadius: 7).cgPath
}
}
代码源: https://gist.github.com/freedom27/c709923b163e26405f62b799437243f4 我只是做了一些更改以消除数字。
答案 11 :(得分:-1)
MIBadgeButton-Swift也在UIBarButtonItems上工作。 以下是创建导航栏后的代码:
let rightBarButtons = self.navigationItem.rightBarButtonItems
let alarmsBarButton = rightBarButtons?.last
let alarmsButton = alarmsBarButton.customView as! MIBadgeButton?
alarmsButton.badgeString = "10"