Files
Woka_Native_iOS/WOKA/BadgedBarButtonItem.swift

215 lines
6.5 KiB
Swift
Raw Normal View History

//
// BadgedBarButtonItem.swift
// BadgedBarButtonItem
//
// Created by Maksim Artemov on 17/07/2019.
// Copyright © 2019 Max. All rights reserved.
//
import UIKit
public enum BadgePosition {
case left
case right
}
public enum BadgeSize {
case extraSmall
case small
case medium
case large
}
// Define the notification name
extension Notification.Name {
static let badgeValueDidChange = Notification.Name("badgeValueDidChange")
}
public class BadgedButtonItem: UIBarButtonItem {
public func setBadge(with value: Int?) {
self.badgeValue = value
}
public var badgeTintColor: UIColor? {
didSet {
lblBadge.backgroundColor = badgeTintColor
}
}
public var badgeTextColor: UIColor? {
didSet {
lblBadge.textColor = badgeTextColor
}
}
public var position: BadgePosition? = .right {
didSet {
if position == .left {
self.lblBadge.frame = CGRect(x: 0,
y: 0,
width: badgeRadius * 2,
height: badgeRadius * 2)
} else {
self.lblBadge.frame = CGRect(x: filterBtn.frame.maxX - badgeRadius * 2 - 5,
y: 0,
width: badgeRadius * 2,
height: badgeRadius * 2)
}
}
}
public var hasBorder: Bool? {
didSet {
if hasBorder == true {
lblBadge.layer.borderWidth = 1.0
}
}
}
public var borderColor: UIColor? = .black {
didSet {
lblBadge.layer.borderColor = borderColor?.cgColor
}
}
public var badgeSize: BadgeSize = .medium {
didSet {
switch badgeSize {
case .extraSmall:
self.badgeRadius = 6.0
case .small:
self.badgeRadius = 7.0
case .medium:
self.badgeRadius = 8.0
case .large:
self.badgeRadius = 9.0
}
}
}
public var badgeAnimation: Bool? = false {
didSet {
self.isAnimated = badgeAnimation
}
}
public var tapAction: (() -> Void)?
private var badgeValue: Int? {
didSet {
if let value = badgeValue, value > 0 {
// reducing font size if the value has two digits
if "\(value)".count > 1 {
lblBadge.font = UIFont.systemFont(ofSize: twoDigitsFontSize)
} else {
lblBadge.font = UIFont.systemFont(ofSize: oneDigitFontSize)
}
lblBadge.isHidden = false
lblBadge.text = "\(value)"
animateBadge(isAnimated)
} else {
lblBadge.isHidden = true
}
// Post notification about the change
NotificationCenter.default.post(name: .badgeValueDidChange, object: nil, userInfo: ["badgeValue": badgeValue ?? 0])
}
}
private let filterBtn = UIButton()
private let lblBadge = UILabel()
private var isAnimated: Bool? = false
private var badgeRadius: CGFloat = 8.0 {
didSet {
self.lblBadge.layer.cornerRadius = badgeRadius
}
}
private var oneDigitFontSize: CGFloat {
return badgeRadius + 1
}
private var twoDigitsFontSize: CGFloat {
return badgeRadius
}
override init() {
super.init()
setup()
}
init(with image: UIImage?) {
super.init()
setup(image: image)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
private func setup(image: UIImage? = nil) {
self.filterBtn.frame = CGRect(x: 0, y: 0, width: 55, height: 55)
self.filterBtn.adjustsImageWhenHighlighted = false
let scaledImage = UIImage.imageWithImage(image, scaledToSize: CGSize(width: 45, height: 50))
self.filterBtn.setImage(scaledImage?.withRenderingMode(.alwaysOriginal), for: .normal)
self.filterBtn.addTarget(self, action: #selector(buttonPressed), for: .touchUpInside)
self.lblBadge.frame = CGRect(x: filterBtn.frame.maxX - badgeRadius * 2,
y: 0,
width: badgeRadius * 2,
height: badgeRadius * 2)
self.lblBadge.backgroundColor = .red
self.lblBadge.clipsToBounds = true
self.lblBadge.layer.cornerRadius = badgeRadius
self.lblBadge.textColor = .white
self.lblBadge.font = UIFont.systemFont(ofSize: 10)
self.lblBadge.textAlignment = .center
self.lblBadge.isHidden = true
self.lblBadge.minimumScaleFactor = 0.5
self.lblBadge.adjustsFontSizeToFitWidth = true
self.filterBtn.addSubview(lblBadge)
self.customView = filterBtn
}
@objc private func buttonPressed() {
if let action = tapAction {
action()
}
}
private func animateBadge(_ animate: Bool?) {
guard animate == true else { return }
lblBadge.transform = CGAffineTransform(scaleX: 1.2, y: 1.2)
UIView.animate(withDuration: 0.4,
delay: 0,
usingSpringWithDamping: 0.2,
initialSpringVelocity: 3,
options: [.curveLinear],
animations: { [weak self] in
guard let strongSelf = self else { return }
strongSelf.lblBadge.transform = .identity
}) { [weak self] (finished) in
guard let strongSelf = self else { return }
if !finished {
strongSelf.lblBadge.transform = .identity
}
}
}
}
/// Takes an image and returns a new one identical but resized.
private extension UIImage {
static func imageWithImage(_ image: UIImage?, scaledToSize newSize: CGSize) -> UIImage? {
guard let image = image else { return nil }
UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0)
image.draw(in: CGRect(origin: CGPoint.zero, size: CGSize(width: newSize.width, height: newSize.height)))
let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return newImage
}
}