Swift добавить значок к навигации barButtonItem и UIButton
Я пытаюсь отобразить значок на кнопке уведомления в приложении, как показано на AppIcon.
Пока все, что я исследовал, связано с Obj. С, но ничего, что конкретно обсуждалось, как внедрить это решение в Swift,
Пожалуйста, помогите найти решение, чтобы добавить пользовательский класс/код для достижения Badge на UiBarbutton и UiButton.
Пока исследовано:
https://github.com/Marxon13/M13BadgeView
наряду с классом MKBadge и т.д.
Ответы
Ответ 1
Существует более элегантное решение с расширением для 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 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()
}
}
Этот отличный код был создан Стефано Веттором, и вы можете найти все подробности по адресу: https://gist.github.com/freedom27/c709923b163e26405f62b799437243f4
Ответ 2
Рабочее решение:
Шаг 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")
Ответ 3
Для UIBarButtonItem
вы можете попробовать этот проект:
ENMBadgeBarButtonItem
Ответ 4
используя M13BadgeView.. используйте этот код
(im используя fontawesome.swift для кнопок:: 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
Ответ 5
Хороший ответ @Джулио Бэйлон (fooobar.com/questions/621406/...)!
Вот автор сайта с полным объяснением: http://www.stefanovettor.com/2016/04/30/adding-badge-uibarbuttonitem/.
Кажется, он не работает на iOS 11, возможно, потому что скрипт пытается получить доступ к свойству "view" 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 }
Кажется элегантным для меня, и, что лучше всего, это сработало!
Ответ 6
У меня была такая же задача. Я не хотел использовать сторонние библиотеки. Во-первых, я попробовал решение Stefano, и оно здорово, но я решил реализовать свой собственный способ его решения.
По моему скромному мнению, есть простые шаги, кратко описанные ниже:
- Создание
UIView
экземпляра в .xib
файла и поместить необходимые элементы, как UILabel
или UIImageView
например, в зависимости от ваших требований к конструкции. ![enter image description here]()
Последнее действие, которое я сделал на этом шаге, - поместил невидимую кнопку в верхнюю часть иерархии представления.
![enter image description here]()
- Создайте
YourCustomView.swift
и свяжите все @IBOutlets
из xib
с текущим файлом внутри реализации вашего пользовательского класса представления.
![enter image description here]()
- Затем, реализуйте функцию класса в классе
YourCustomView
который будет загружать пользовательский вид из xib и возвращать его как экземпляр YourCustomView
.
![enter image description here]()
- Наконец, добавьте свой собственный значок в свой экземпляр контроллера представления!
![enter image description here]()
Мой результат..
![enter image description here]()
PS Если вам нужно реализовать @IBActions
я рекомендую связать ваш пользовательский вид и контроллер пользовательского вида через шаблон делегата.
Ответ 7
Вы можете установить следующие ограничения для UILabel
относительно UIButton
выровнять верх UILabel
и трейлинг UIButton
И когда вам нужно показать значок, установите текст в UILabel
а когда вы не хотите показывать значок, тогда установите пустую строку в UILabel
Ответ 8
Скачать это
Для 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
Вот простое решение Swift 4 с некоторыми настройками https://github.com/Syngmaster/BadgedBarButtonItem
Ответ 10
Ответить с расширением от Хулио не получится.
Начиная с iOS 11 этот код не будет работать, потому что строка кода ниже не приведёт к UIView. Также он считается частным API и, похоже, не пройдет проверку AppStore.
guard let view = self.value(forKey: "view") as? UIView else { return }
Тема на форуме разработчиков Apple
Во-вторых, этот фрагмент всегда рисует круг, поэтому он не может соответствовать числам больше 9.
Ответ 11
MIBadgeButton-Swift также работает с UIBarButtonItems.
Вот мой код после создания панели навигации:
let rightBarButtons = self.navigationItem.rightBarButtonItems
let alarmsBarButton = rightBarButtons?.last
let alarmsButton = alarmsBarButton.customView as! MIBadgeButton?
alarmsButton.badgeString = "10"
Ответ 12
Вы можете сделать это программно с
self.tabBarItem.badgeColor = .red
или используйте раскадровку. Увидеть:
![storyboard]()