Reputation: 4570
I want to add/set unread flag as red dot top right corner on UIbarButtonItem
, See attached image for this
What should i do to add/set red dot on Bar Button item? Once user tap on item then i want to remove red dot.
Upvotes: 3
Views: 3349
Reputation: 451
let dotView = UIView()
let btnSize =yourBarbutton.frame.size
let dotSize = 8
dotView.backgroundColor = .red //Just change colors
dotView.layer.cornerRadius = CGFloat(dotSize/2)
dotView.layer.frame = CGRect(x: Int(btnSize.width)-dotSize/2 , y:
dotSize, width: dotSize, height: dotSize)
yourBarbutton.addSubview(dotView)
Upvotes: 1
Reputation: 11210
Okay, let's start with creating custom UIButton
subclass
class ButtonWithBadge: UIButton {
}
now let's create UIView
for repsenting red dot
let badgeView: UIView = {
let view = UIView()
view.layer.cornerRadius = 3
view.backgroundColor = .red
return view
}()
Then override init
for this subclass and inside add this badgeView
to top right corner of your button: set its constraints (right and top equal to button's anchors and width and height to double of badgeView
's cornerRadius value)
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(badgeView)
badgeView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
badgeView.rightAnchor.constraint(equalTo: rightAnchor, constant: 3),
badgeView.topAnchor.constraint(equalTo: topAnchor, constant: 3),
badgeView.heightAnchor.constraint(equalToConstant: badgeView.layer.cornerRadius*2),
badgeView.widthAnchor.constraint(equalToConstant: badgeView.layer.cornerRadius*2)
])
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
Next create variable represeting current state of button:
var isRead: Bool = false
Now let's create some method which hide or unhide badgeView
depending on isRead
value
func setBadge() {
badgeView.isHidden = isRead
}
Now we have function, right? So let's call this function at the end of init
and in didSet
of isRead
variable
class ButtonWithProperty: UIButton {
var isRead: Bool = false {
didSet {
setBadge()
}
}
override init(frame: CGRect) {
...
setBadge()
}
First create variables for button and view
lazy var barButton: ButtonWithProperty = {
let button = ButtonWithProperty()
... // set color, title, target, etc.
return button
}()
now for example in viewDidLoad
add this barButton
to UINavigationBar
and position it how you want to:
override func viewDidLoad() {
super.viewDidLoad()
...
guard let navigationBar = self.navigationController?.navigationBar else { return }
navigationBar.addSubview(barButton)
barButton.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
barButton.rightAnchor.constraint(equalTo: navigationBar.rightAnchor, constant: -20),
barButton.bottomAnchor.constraint(equalTo: navigationBar.bottomAnchor, constant: -6)
])
}
Now when you need to, you can just easily change barButton
's isRead
variable and red dot disappears or appears
barButton.isRead = true
class ButtonWithProperty: UIButton {
var isRead: Bool = false {
didSet {
setBadge()
}
}
lazy var badgeView: UIView = {
let view = UIView()
view.layer.cornerRadius = 3
view.backgroundColor = .red
return view
}()
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(badgeView)
badgeView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
badgeView.rightAnchor.constraint(equalTo: rightAnchor, constant: 3),
badgeView.topAnchor.constraint(equalTo: topAnchor, constant: 3),
badgeView.heightAnchor.constraint(equalToConstant: badgeView.layer.cornerRadius*2),
badgeView.widthAnchor.constraint(equalToConstant: badgeView.layer.cornerRadius*2)
])
setBadge()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setBadge() {
badgeView.isHidden = isRead
}
}
Inside ViewController:
class ViewController: UIViewController {
lazy var barButton: ButtonWithProperty = {
let button = ButtonWithProperty()
... // color, title, target, etc.
return button
}()
...
override func viewDidLoad() {
super.viewDidLoad()
...
guard let navigationBar = self.navigationController?.navigationBar else { return }
navigationBar.addSubview(barButton)
barButton.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
barButton.rightAnchor.constraint(equalTo: navigationBar.rightAnchor, constant: -20),
barButton.bottomAnchor.constraint(equalTo: navigationBar.bottomAnchor, constant: -6)
])
}
...
}
Upvotes: 5
Reputation: 107231
I've written a custom bar button class to handle this, where I'm using CAShapeLayer
to draw a dot on top of the UIBarButtonItem
.
// Custom Bar button
class CustomBarButton: UIBarButtonItem
{
// Unread Mark
private var unreadMark: CAShapeLayer?
// Keep track of unread status
var hasUnread: Bool = false
{
didSet
{
setUnread(hasUnread: hasUnread)
}
}
// Toggles unread status
private func setUnread(hasUnread: Bool)
{
if hasUnread
{
unreadMark = CAShapeLayer();
unreadMark?.path = UIBezierPath(ovalIn: CGRect(x: (self.customView?.frame.width ?? 0) - 10, y: 5, width: 5, height: 5)).cgPath;
unreadMark?.fillColor = UIColor.red.cgColor
self.customView?.layer.addSublayer(unreadMark!)
}
else
{
unreadMark?.removeFromSuperlayer()
}
}
}
There is no layer property available for bar button item, so you need to create your UIBarButtonItem
using a custom view:
// Bar button property
var barButton:CustomBarButton!
// Initialisation
button = UIButton(type: .custom)
button.frame = CGRect(x: 0, y: 0, width: 70, height: 40)
button.setTitle("Right", for: .normal)
button.setTitleColor(UIColor.green, for: .normal)
// Bar button
barButton = CustomBarButton(customView: button)
button.addTarget(self, action: #selector(toggleStatus(sender:)), for: UIControl.Event.touchUpInside)
// Flexible space (Optional)
let flexibleSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
toolBar.items = [flexibleSpace, barButton]
And in the IBAction
you can toggle the status using the hasUnread
property:
@objc func toggleStatus(sender: AnyObject)
{
barButton.hasUnread = !barButton.hasUnread
}
And it will look like:
Upvotes: 2