Rounded UILabel and UIButton, Badged UIBarButtonItem
// | |
// Badge.swift | |
// Extensions for Rounded UILabel and UIButton, Badged UIBarButtonItem. | |
// | |
// Usage: | |
// let label = UILabel(badgeText: "Rounded Label"); | |
// let button = UIButton(type: .System); button.rounded = true | |
// let barButton = UIBarButtonItem(badge: "42", title: "How Many Roads", target: self, action: "answer") | |
// | |
// Created by Yonat Sharon on 06.04.2015. | |
// Copyright (c) 2015 Yonat Sharon. All rights reserved. | |
// | |
import UIKit | |
public extension UILabel { | |
public convenience init(badgeText: String, color: UIColor = .red, fontSize: CGFloat = UIFont.smallSystemFontSize) { | |
self.init() | |
text = badgeText.count > 1 ? " \(badgeText) " : badgeText | |
textAlignment = .center | |
textColor = .white | |
backgroundColor = color | |
font = UIFont.systemFont(ofSize: fontSize) | |
layer.cornerRadius = fontSize * CGFloat(0.6) | |
clipsToBounds = true | |
translatesAutoresizingMaskIntoConstraints = false | |
addConstraint(NSLayoutConstraint(item: self, attribute: .width, relatedBy: .greaterThanOrEqual, toItem: self, attribute: .height, multiplier: 1, constant: 0)) | |
} | |
} | |
extension UIButton { | |
/// show background as rounded rect, like mail addressees | |
public var rounded: Bool { | |
get { return layer.cornerRadius > 0 } | |
set { roundWithTitleSize(newValue ? titleSize : 0) } | |
} | |
/// removes other title attributes | |
public var titleSize: CGFloat { | |
get { | |
let titleFont = attributedTitle(for: .normal)?.attribute(.font, at: 0, effectiveRange: nil) as? UIFont | |
return titleFont?.pointSize ?? UIFont.buttonFontSize | |
} | |
set { | |
if UIFont.buttonFontSize == newValue || 0 == newValue { | |
setTitle(currentTitle, for: .normal) | |
} else { | |
let attrTitle = NSAttributedString(string: currentTitle ?? "", attributes: | |
[.font: UIFont.systemFont(ofSize: newValue), .foregroundColor: currentTitleColor]) | |
setAttributedTitle(attrTitle, for: .normal) | |
} | |
if rounded { | |
roundWithTitleSize(newValue) | |
} | |
} | |
} | |
/// regular `setTitle()` fails after using `setAttributedTitle()` (which called if you changed `titleSize`) | |
public func changeTitleButKeepAttributes(_ newTitle: String) { | |
setAttributedTitle(nil, for: .normal) | |
setTitle(newTitle, for: .normal) | |
} | |
func roundWithTitleSize(_ size: CGFloat) { | |
let padding = size / 4 | |
layer.cornerRadius = padding + size * 1.2 / 2 | |
let sidePadding = padding * 1.5 | |
contentEdgeInsets = UIEdgeInsets(top: padding, left: sidePadding, bottom: padding, right: sidePadding) | |
if size.isZero { | |
backgroundColor = .clear | |
setTitleColor(tintColor, for: .normal) | |
} else { | |
backgroundColor = tintColor | |
let currentTitleColor = titleColor(for: .normal) | |
if currentTitleColor == nil || currentTitleColor == tintColor { | |
setTitleColor(.white, for: .normal) | |
} | |
} | |
} | |
// swiftlint:disable override_in_extension | |
open override func tintColorDidChange() { | |
super.tintColorDidChange() | |
if rounded { | |
backgroundColor = tintColor | |
} | |
} | |
// swiftlint:enable override_in_extension | |
} | |
public extension UIBarButtonItem { | |
convenience init(badge: String?, title: String, target: AnyObject?, action: Selector) { | |
let button = UIButton(type: .system) | |
button.setTitle(title, for: .normal) | |
button.titleLabel?.font = UIFont.systemFont(ofSize: UIFont.buttonFontSize) | |
button.addTarget(target, action: action, for: .touchUpInside) | |
button.sizeToFit() | |
if let badge = badge { | |
let badgeLabel = UILabel(badgeText: badge) | |
button.addSubview(badgeLabel) | |
button.addConstraint(NSLayoutConstraint(item: badgeLabel, attribute: .top, relatedBy: .equal, toItem: button, attribute: .top, multiplier: 1, constant: 0)) | |
button.addConstraint(NSLayoutConstraint(item: badgeLabel, attribute: .centerX, relatedBy: .equal, toItem: button, attribute: .trailing, multiplier: 1, constant: 0)) | |
} | |
self.init(customView: button) | |
} | |
var badgeLabel: UILabel? { | |
return customView?.viewWithTag(UIBarButtonItem.badgeTag) as? UILabel | |
} | |
var badgedButton: UIButton? { | |
return customView as? UIButton | |
} | |
var badgeString: String? { | |
get { return badgeLabel?.text?.trimmingCharacters(in: .whitespaces) } | |
set { | |
if let badgeLabel = badgeLabel { | |
badgeLabel.text = nil == newValue ? nil : " \(newValue!) " | |
badgeLabel.sizeToFit() | |
badgeLabel.isHidden = nil == newValue | |
} | |
} | |
} | |
var badgedTitle: String? { | |
get { return badgedButton?.title(for: .normal) } | |
set { badgedButton?.setTitle(newValue, for: .normal); badgedButton?.sizeToFit() } | |
} | |
private static let badgeTag = 7373 | |
} |
This comment has been minimized.
This comment has been minimized.
Nice code, thx for sharing! I added an extra
|
This comment has been minimized.
This comment has been minimized.
This is great. Looked all over for a nifty solution; this is it. Thanks a million! |
This comment has been minimized.
This comment has been minimized.
I have made a fork with an update to Swift 3.0: https://gist.github.com/MagnusNordin/de81ead08cfbc33796ffd71649292ca6 |
This comment has been minimized.
This comment has been minimized.
Swift 4 and sub-class, etc. updates:
Example usage:
|
This comment has been minimized.
This comment has been minimized.
@basememara this doesn't work. I just get an 'ambiguous' error |
This comment has been minimized.
This comment has been minimized.
|
This comment has been minimized.
This comment has been minimized.
swift 4.2
|
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This comment has been minimized.
do you have a sample implementation?