Skip to content

Instantly share code, notes, and snippets.

@arpitdsoni
Created November 26, 2019 19:57
Show Gist options
  • Save arpitdsoni/24c4b683902e1241345b9cf4c5ff4781 to your computer and use it in GitHub Desktop.
Save arpitdsoni/24c4b683902e1241345b9cf4c5ff4781 to your computer and use it in GitHub Desktop.
import UIKit
class HyperlinkLabel: UILabel {
var stringAndUrl: [String: URL] = [:] {
didSet {
attributedText = attributedText()
}
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
override func awakeFromNib() {
super.awakeFromNib()
commonInit()
}
func commonInit() {
numberOfLines = 0
isUserInteractionEnabled = true
let tap = UITapGestureRecognizer(target: self, action: #selector(linkTapped(gesture:)))
addGestureRecognizer(tap)
}
}
fileprivate extension HyperlinkLabel {
@objc func linkTapped(gesture: UITapGestureRecognizer) {
guard let text = self.text as NSString? else {
return
}
for (string, url) in stringAndUrl {
let range = text.localizedStandardRange(of: string)
let tapLocation = gesture.location(in: self)
let index = self.indexOfAttributedTextCharacterAtPoint(point: tapLocation)
if checkRange(range, containsIndex: index) {
SafariManager.show(url)
return
}
}
}
func attributedText() -> NSAttributedString {
guard let text = self.text else {
return NSAttributedString(string: "")
}
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = textAlignment
let attributedString =
NSMutableAttributedString(string: text, attributes: [
.paragraphStyle: paragraphStyle,
.font: self.font as Any
])
let boldFontAttribute = [
NSAttributedString.Key.font: self.font.bold(),
NSAttributedString.Key.foregroundColor: UIColor.tintColor
]
for str in stringAndUrl.keys {
attributedString.addAttributes(boldFontAttribute, range: (text as NSString).range(of: str))
}
return attributedString
}
func indexOfAttributedTextCharacterAtPoint(point: CGPoint) -> Int {
guard let attributedText = attributedText else {
preconditionFailure("This method is developed for attributed string")
}
let textStorage = NSTextStorage(attributedString: attributedText)
let layoutManager = NSLayoutManager()
textStorage.addLayoutManager(layoutManager)
let textContainer = NSTextContainer(size: self.frame.size)
textContainer.lineFragmentPadding = 0
textContainer.maximumNumberOfLines = self.numberOfLines
textContainer.lineBreakMode = self.lineBreakMode
layoutManager.addTextContainer(textContainer)
let index = layoutManager.characterIndex(for: point, in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
return index
}
func checkRange(_ range: NSRange, containsIndex index: Int) -> Bool {
return index > range.location && index < range.location + range.length
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment