A simple to use drop in replacement for UILabel written in Swift that provides automatic detection of links such as URLs, phone numbers, twitter style usernames and hashtags.
ContextLabel doesn't have any special dependencies so just include the files ContextLabel.swift in your project. Then use the ContextLabel
class in replacement for UILabel
.
ContextLabel supports both, delegates and closures. Once a delegate is set, closures are ignored.
From version 1.3 you can optionally set a different font for each linkresult by returning a font within the closure or delegate:
contextLabel.textFont = { (linkResult) in
return UIFont.systemFont(ofSize: 16)
}
func contextLabel(_ sender: ContextLabel, textFontForLinkResult linkResult: LinkResult) -> UIFont {
return UIFont.systemFont(ofSize: 16)
}
ContextLabel supports different colors for URLs, twitter style usernames and hashtags. By default the link text colors are set to userHandle RGB(71,90,109), hashtag RGB(151, 154, 158) and url/email/text links RGB(45, 113, 178) when using closures.
To set your own text colors, return the desired UIColor within the closure or delegate:
contextLabel.foregroundColor = { (linkResult) in
switch linkResult.detectionType {
case .userHandle:
return UIColor(red: 71.0/255.0, green: 90.0/255.0, blue: 109.0/255.0, alpha: 1.0)
case .hashtag:
return UIColor(red: 151.0/255.0, green: 154.0/255.0, blue: 158.0/255.0, alpha: 1.0)
case .url, .email:
return UIColor(red: 45.0/255.0, green: 113.0/255.0, blue: 178.0/255.0, alpha: 1.0)
case .textLink:
return UIColor(red: 45.0/255.0, green: 113.0/255.0, blue: 178.0/255.0, alpha: 1.0)
case .phoneNumber:
return UIColor(red: 45.0/255.0, green: 113.0/255.0, blue: 178.0/255.0, alpha: 1.0)
default:
return .black
}
}
func contextLabel(_ sender: ContextLabel, foregroundColorForLinkResult linkResult: LinkResult) -> UIColor {
return sender.foregroundColor(linkResult)
}
If there is no UIColor returned from foregroundHighlightedColor
, an alpha of 0.5 is applied to the set text color when a link is detected.
To set your own text highlight colors, return the desired UIColor within the closure or delegate:
contextLabel.foregroundHighlightedColor = { (linkResult) in
return .lightGray
}
func contextLabel(_ sender: ContextLabel, foregroundHighlightedColorForLinkResult linkResult: LinkResult) -> UIColor {
return sender.foregroundHighlightedColor(linkResult)
}
By default detected links are not underlined.
To set your own underline style, return the desired NSUnderlineStyle within the closure or delegate:
contextLabel.underlineStyle = { (linkResult) in
return .styleNone
}
func contextLabel(_ sender: ContextLabel, underlineStyleForLinkResult linkResult: LinkResult) -> NSUnderlineStyle
return sender.underlineStyle(linkResult)
}
From version 1.3 you can also modify the attributed string before it gets finally applied to the label via the following closure or delegate:
contextLabel.modifiedAttributedString = { (attributedString) in
var _attributedString = attributedString
// Modify attributes
return _attributedString
}
func contextLabel(_ sender: ContextLabel, modifiedAttributedString attributedString: NSAttributedString) -> NSAttributedString {
var _attributedString = modifiedAttributedString
// Modify attributes
return _attributedString
}
When tapping the label, the closure didTouch: (TouchResult) -> Void
will be called for each touch state:
didTouch: { [weak self] (touchResult) in
switch touchResult.state {
case .began:
// Do something
case .ended:
// Do something
default:
break
}
}
From version 1.3.0 you can alternativly implement the delegate:
func contextLabel(_ sender: ContextLabel, didTouchWithTouchResult touchResult: TouchResult) {
switch touchResult.state {
case .began:
// Do something
case .ended:
// Do something
default:
break
}
}
The touch behaviour changed from version 1.2.0.
The touchResult
includes everything you need to take action on the selected string.
public struct TouchResult {
public let linkResult: LinkResult?
public let touches: Set<UITouch>
public let event: UIEvent?
public let state: UIGestureRecognizerState
}
public struct LinkResult {
public let detectionType: ContextLabel.LinkDetectionType
public let range: NSRange
public let text: String
public let textLink: TextLink?
}
public enum LinkDetectionType {
case none
case userHandle
case hashtag
case url
case email
case textLink
case phoneNumber
}
To allow copying of text into pastboard via longpress set contextLabel.canCopy = true
and implement the following closure or delegate:
contextLabel.didCopy = { (text) in
}
func contextLabel(_ sender: ContextLabel, didCopy text: String?) {
}
ContextLabel automatically recognizes words starting with # and @ as well as manually defined text links.
A text link is defined at the minimum by a string ”text link”
and an action which is a closure that gets called when the user touches the defined text. From version 0.3.1, all occurencies of a given text are recognized within the label text. To limit the recognition within the label text, an optional range can be set when initializing a TextLink.
TextLink(text: String, range: NSRange? = nil, options: NSString.CompareOptions = [], action: @escaping ()->())
When setting the text, ContextLabel generates an instance of ’ContextLabelData’ which is a NSObject subclass that can be persisted in order to enable reuse for unchanged data.
’ContextLabelData’ holds the actual attributedString
, the linkRangeResults
and a userInfo dictionary which can be used to compare against the model data to see if it’s still valid.
if let cachedContextLabelData: ContextLabelData = … {
// Set cached contextLabelData
contextLabel.contextLabelData = cachedTextContextLabelData
} else {
// Set label text
contextLabel.text = text
// Cache contextLabelData that has been generated from contextLabel
cacheContextLabelData(contextLabel.contextLabelData)
}
While contributions are always welcome, do not expect a lot of feature evolution beyond the current state. Feel free to fork this library or open pull requests if you'd like to add new features or need fixes and Swift updates.
ContextLabel is is released under the MIT License. ContextLabel was inspired by KILabel (https://github.com/Krelborn/KILabel).