Skip to content

Instantly share code, notes, and snippets.

@gali8
Created September 9, 2019 15:20
Show Gist options
  • Save gali8/c932429dc92c0e01961d0331063180e5 to your computer and use it in GitHub Desktop.
Save gali8/c932429dc92c0e01961d0331063180e5 to your computer and use it in GitHub Desktop.
import UIKit
class LabelTappable: UILabel {
let layoutManager = NSLayoutManager()
let textContainer = NSTextContainer(size: CGSize.zero)
let tapGesture = UITapGestureRecognizer()
var textStorage = NSTextStorage() {
didSet {
textStorage.addLayoutManager(layoutManager)
}
}
var didTap: ((_ label: UILabel, _ characterIndex: Int) -> Void)?
override var attributedText: NSAttributedString? {
didSet {
if let attributedText = attributedText {
textStorage = NSTextStorage(attributedString: attributedText)
} else {
textStorage = NSTextStorage()
}
}
}
override var lineBreakMode: NSLineBreakMode {
didSet {
textContainer.lineBreakMode = lineBreakMode
}
}
override var numberOfLines: Int {
didSet {
textContainer.maximumNumberOfLines = numberOfLines
}
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setUp()
}
override init(frame: CGRect) {
super.init(frame: frame)
setUp()
}
func setUp() {
isUserInteractionEnabled = true
layoutManager.addTextContainer(textContainer)
textContainer.lineFragmentPadding = 0
textContainer.lineBreakMode = lineBreakMode
textContainer.maximumNumberOfLines = numberOfLines
tapGesture.addTarget(self, action: #selector(LabelTappable.labelTapped(_:)))
addGestureRecognizer(tapGesture)
}
override func layoutSubviews() {
super.layoutSubviews()
textContainer.size = bounds.size
}
@objc func labelTapped(_ gesture: UITapGestureRecognizer) {
guard gesture.state == .ended else {
return
}
let locationOfTouch = gesture.location(in: gesture.view)
let textBoundingBox = layoutManager.usedRect(for: textContainer)
let textContainerOffset = CGPoint(
x: (bounds.width - textBoundingBox.width) / 2 - textBoundingBox.minX,
y: (bounds.height - textBoundingBox.height) / 2 - textBoundingBox.minY
)
let locationOfTouchInTextContainer = CGPoint(
x: locationOfTouch.x - textContainerOffset.x,
y: locationOfTouch.y - textContainerOffset.y
)
let characterIndex = layoutManager.characterIndex(for: locationOfTouchInTextContainer,
in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
/* HOW TO USE */
/*
es for links
self.didTap = { [weak self] label, characterIndex in
guard let _ = self else {
return
}
if let url = label.attributedText?.attribute(.link, at: characterIndex, effectiveRange: nil) as? URL, UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
}
*/
didTap?(self, characterIndex)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment