Skip to content

Instantly share code, notes, and snippets.

@arpitdsoni
Last active September 16, 2020 16:46
Show Gist options
  • Save arpitdsoni/dd03ba144c9d3c6db04ca348d18be206 to your computer and use it in GitHub Desktop.
Save arpitdsoni/dd03ba144c9d3c6db04ca348d18be206 to your computer and use it in GitHub Desktop.
protocol HyperLinkTextViewDelegate: class {
func textView(textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool
}
/// converts text to attributedText with clickable strings
class HyperLinkTextView: UITextView, UITextViewDelegate {
weak var hyperLinkTextViewDelegate: HyperLinkTextViewDelegate?
var additionalAttributesForLinkText: [NSAttributedString.Key : Any] = [:]
var stringAndUrl: [String: URL] = [:] {
didSet {
attributedText = attributedText()
}
}
override init(frame: CGRect, textContainer: NSTextContainer?) {
super.init(frame: frame, textContainer: textContainer)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
override func awakeFromNib() {
super.awakeFromNib()
commonInit()
}
func commonInit() {
delegate = self
isEditable = false
dataDetectorTypes = [.link]
}
private func attributedText() -> NSAttributedString {
guard let text = self.text else {
return NSAttributedString(string: "")
}
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = textAlignment
var attributedString = NSMutableAttributedString(string: text, attributes: [
NSAttributedString.Key.foregroundColor: UIColor.primarySystemLabelColor,
.paragraphStyle: paragraphStyle,
.font: self.font as Any
])
if let existingAttributedString = self.attributedText { //If there existing attributedText, don't apply new attributes
attributedString = NSMutableAttributedString(attributedString: existingAttributedString)
}
for (str, url) in stringAndUrl {
let range = (text as NSString).range(of: str)
attributedString.addAttribute(.link, value: url, range: range)
additionalAttributesForLinkText.forEach { (attributeName, value) in
attributedString.addAttribute(attributeName, value: value, range: range)
}
}
return attributedString
}
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
guard let pos = closestPosition(to: point) else { return false }
guard let range = tokenizer.rangeEnclosingPosition(pos, with: .character, inDirection: .layout(.left)) else { return false }
let startIndex = offset(from: beginningOfDocument, to: range.start)
return attributedText.attribute(.link, at: startIndex, effectiveRange: nil) != nil
}
// MARK: UITextViewDelegate
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
if let hyperLinkTextViewDelegate = hyperLinkTextViewDelegate {
return hyperLinkTextViewDelegate.textView(textView: textView, shouldInteractWith: URL, in: characterRange, interaction: interaction)
} else {
return false
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment