Created
January 10, 2017 07:10
-
-
Save jhonny-me/38b34eae77b73fe02605b96b4f07cbf9 to your computer and use it in GitHub Desktop.
Mutilple links in Label
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// MLLabel.swift | |
// Starbucks | |
// | |
// Created by Johnny Gu on 09/01/2017. | |
// Copyright © 2017 Wiredcraft. All rights reserved. | |
// | |
import UIKit | |
class MLLabel: UILabel { | |
/* | |
// Only override draw() if you perform custom drawing. | |
// An empty implementation adversely affects performance during animation. | |
override func draw(_ rect: CGRect) { | |
// Drawing code | |
} | |
*/ | |
override init(frame: CGRect) { | |
super.init(frame: frame) | |
isUserInteractionEnabled = true | |
} | |
required init?(coder aDecoder: NSCoder) { | |
super.init(coder: aDecoder) | |
isUserInteractionEnabled = true | |
} | |
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { | |
guard let attributedText = attributedText else { return } | |
let wholeRange = NSMakeRange(0, attributedText.length) | |
attributedText.enumerateAttribute(NSLinkAttributeName, in: wholeRange, options: []) { [weak self] (url, range, stop) in | |
if url == nil { return } | |
self?.boundingRectsForCharacterRange(range, using: { (rects) in | |
if | |
let point = touches.first?.location(in: self), | |
rects.contains(point){ | |
stop.pointee = true | |
if let url = url as? URL{ | |
if (UIApplication.shared.canOpenURL(url)){ | |
UIApplication.shared.openURL(url) | |
} | |
}else if let string = url as? String, let url = URL(string: string) { | |
if (UIApplication.shared.canOpenURL(url)){ | |
UIApplication.shared.openURL(url) | |
} | |
}else { | |
} | |
print(url ?? "ppp") | |
} | |
}) | |
} | |
} | |
} | |
extension UILabel { | |
func boundingRectsForCharacterRange(_ range: NSRange, using block: @escaping ([CGRect])->Void) { | |
guard let attributedText = attributedText else { | |
block([]) | |
return | |
} | |
let textStorage = NSTextStorage(attributedString: attributedText) | |
let layoutManager = NSLayoutManager() | |
textStorage.addLayoutManager(layoutManager) | |
let textContainer = NSTextContainer(size: bounds.size) | |
textContainer.lineFragmentPadding = 0.0 | |
layoutManager.addTextContainer(textContainer) | |
var glyphRange = NSRange() | |
var rects: [CGRect] = [] | |
// Convert the range for glyphs. | |
layoutManager.characterRange(forGlyphRange: range, actualGlyphRange: &glyphRange) | |
layoutManager.enumerateLineFragments(forGlyphRange: glyphRange) { (lineRect, usedRect, container, range, stop) in | |
if let rect = self.rect(for: glyphRange, in: range, whole: lineRect) { | |
rects.append(rect) | |
} | |
if glyphRange.length + glyphRange.location <= range.length + range.location { | |
block(rects) | |
} | |
print(lineRect, usedRect, range.location, range.length, glyphRange.location, glyphRange.length, stop.pointee) | |
} | |
} | |
private func rect(for subRange: NSRange, in range: NSRange, whole rect: CGRect) -> CGRect?{ | |
let intersectionRange = NSIntersectionRange(subRange, range) | |
if intersectionRange.length == 0 { return nil } | |
let x = CGFloat(intersectionRange.location - range.location)/CGFloat(range.length) * rect.width + rect.minX | |
let width = CGFloat(intersectionRange.length)/CGFloat(range.length) * rect.width | |
return CGRect(x: x, y: rect.minY, width: width, height: rect.height) | |
} | |
func boundingRectForCharacterRange(range: NSRange) -> CGRect? { | |
guard let attributedText = attributedText else { return nil } | |
let textStorage = NSTextStorage(attributedString: attributedText) | |
let layoutManager = NSLayoutManager() | |
textStorage.addLayoutManager(layoutManager) | |
let textContainer = NSTextContainer(size: bounds.size) | |
textContainer.lineFragmentPadding = 0.0 | |
layoutManager.addTextContainer(textContainer) | |
var glyphRange = NSRange() | |
// Convert the range for glyphs. | |
layoutManager.characterRange(forGlyphRange: range, actualGlyphRange: &glyphRange) | |
layoutManager.enumerateLineFragments(forGlyphRange: glyphRange) { (lineRect, usedRect, container, range, stop) in | |
// print(lineRect, usedRect, range.location, range.length, glyphRange.location, glyphRange.length) | |
} | |
return layoutManager.boundingRect(forGlyphRange: glyphRange, in: textContainer) | |
} | |
} | |
extension Sequence where Iterator.Element == CGRect { | |
func contains(_ point: CGPoint) -> Bool { | |
var result = false | |
self.forEach({ if $0.contains(point) { result = true }}) | |
return result | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment