textkit结构
textkit使用步骤
#Mark - 1. 自定义label --class CZLabel: UILabel---四个属性
private lazy var textStorage = NSTextStorage()
private lazy var layoutManager = NSLayoutManager()
private lazy var textContainer = NSTextContainer()
private lazy var linkRanges = [NSRange]()
#Mark - 2. 重新init方法-- override init(frame: CGRect) {}
userInteractionEnabled = true
if let attributedText = attributedText {}
textStorage.addLayoutManager(layoutManager)
layoutManager.addTextContainer(textContainer)
#Mark - 3. 外界给label的text属性赋值 label.text = @"@好友,#健康#,....."
let attrStringM = addLineBreak(attributedText!)
regexLinkRanges(attrStringM)
addLinkAttribute(attrStringM)
textStorage.setAttributedString(attrStringM)
setNeedsDisplay()
#Mark - 4. textStorage字形和属性发生变化时,通知NSLayoutManager重新布局文本
override func layoutSubviews() {
super.layoutSubviews()
textContainer.size = bounds.size
}
#Mark - 5. 绘制textStorage的文本内容--不能调用super
override func drawTextInRect(rect: CGRect) {
let range = NSMakeRange(0, textStorage.length)
layoutManager.drawGlyphsForGlyphRange(range, atPoint: CGPoint(x: 0,y: 0))
}
#Mark - 6. 用户点击事件交互
三步法:1.正则表达式 2.创建正则 3.匹配 4.便利匹配结果,添加到属性数组
let location = touches.first?.locationInView(self)
let index = layoutManager.glyphIndexForPoint(location, inTextContainer: textContainer)
for range in atRange ?? [] {
if NSLocationInRange(index, range) {
let strSub = (textStorage.string as NSString).substringWithRange(range)
}
}
Swift使用
import UIKit
class ZYLabel: UILabel {
override var text:String? {
didSet {
if attributedText == nil {
return
}
let attrStringM = addLineBreak(attributedText!)
regexLinkRanges(attrStringM)
addLinkAttribute(attrStringM)
textStorage.setAttributedString(attrStringM)
setNeedsDisplay()
}
}
private lazy var textStorage = NSTextStorage()
private lazy var layoutManager = NSLayoutManager()
private lazy var textContainer = NSTextContainer()
private lazy var linkRanges = [NSRange]()
override init(frame: CGRect) {
super.init(frame: frame)
userInteractionEnabled = true
if let attributedText = attributedText {
textStorage.setAttributedString(attributedText)
}else if let text = text {
textStorage.setAttributedString(NSAttributedString(string: text))
}else {
textStorage.setAttributedString(NSAttributedString(string: ""))
}
textStorage.addLayoutManager(layoutManager)
layoutManager.addTextContainer(textContainer)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
userInteractionEnabled = true
if let attributedText = attributedText {
textStorage.setAttributedString(attributedText)
}else if let text = text {
textStorage.setAttributedString(NSAttributedString(string: text))
}else {
textStorage.setAttributedString(NSAttributedString(string: ""))
}
textStorage.addLayoutManager(layoutManager)
layoutManager.addTextContainer(textContainer)
}
private func addLineBreak(attrString: NSAttributedString) -> NSMutableAttributedString {
let attrStringM = NSMutableAttributedString(attributedString: attrString)
if attrStringM.length == 0 {
return attrStringM
}
var range = NSRange(location: 0, length: 0)
var attributes = attrStringM.attributesAtIndex(0, effectiveRange: &range)
var paragraphStyle = attributes[NSParagraphStyleAttributeName] as? NSMutableParagraphStyle
if paragraphStyle != nil {
paragraphStyle!.lineBreakMode = NSLineBreakMode.ByCharWrapping
} else {
paragraphStyle = NSMutableParagraphStyle()
paragraphStyle!.lineBreakMode = NSLineBreakMode.ByCharWrapping
attributes[NSParagraphStyleAttributeName] = paragraphStyle
attrStringM.setAttributes(attributes, range: range)
}
return attrStringM
}
private func addLinkAttribute(attrStringM: NSMutableAttributedString) {
if attrStringM.length == 0 {
return
}
var range = NSRange(location: 0, length: 0)
var attributes = attrStringM.attributesAtIndex(0, effectiveRange: &range)
attrStringM.addAttributes(attributes, range: range)
attributes[NSForegroundColorAttributeName] = UIColor.blueColor()
for range in linkRanges {
attrStringM.setAttributes(attributes, range: range)
}
}
private let patterns = ["((http[s]{0,1}|ftp)://[a-zA-Z0-9\\.\\-]+\\.([a-zA-Z]{2,4})(:\\d+)?(/[a-zA-Z0-9\\.\\-~!@#$%^&*+?:[a-zA-Z0-9]{3}_/=<>]*)?)|(www.[a-zA-Z0-9\\.\\-]+\\.([a-zA-Z]{2,4})(:\\d+)?(/[a-zA-Z0-9\\.\\-~!@#$%^&*+?:_/=<>]*)?)", "#.*?#", "@[\\u4e00-\\u9fa5a-zA-Z0-9_-]*"]
private func regexLinkRanges(attrString: NSAttributedString) {
linkRanges.removeAll()
let regexRange = NSRange(location: 0, length: attrString.string.characters.count)
for pattern in patterns {
let regex = try! NSRegularExpression(pattern: pattern, options: .DotMatchesLineSeparators)
let results = regex.matchesInString(attrString.string, options:NSMatchingOptions(rawValue: 0) , range: regexRange)
for range in results {
linkRanges.append(range.rangeAtIndex(0))
}
}
}
override func layoutSubviews() {
super.layoutSubviews()
textContainer.size = bounds.size
}
override func drawTextInRect(rect: CGRect) {
let range = NSMakeRange(0, textStorage.length)
layoutManager.drawGlyphsForGlyphRange(range, atPoint: CGPoint(x: 0,y: 0))
}
override func touchesBegan(touches: Set, withEvent event: UIEvent?) {
guard let location = touches.first?.locationInView(self) else {
return
}
let index = layoutManager.glyphIndexForPoint(location, inTextContainer: textContainer)
for range in atRange ?? [] {
if NSLocationInRange(index, range) {
let strSub = (textStorage.string as NSString).substringWithRange(range)
print(strSub)
}
}
for range in jingRange ?? [] {
if NSLocationInRange(index, range) {
let strSub = (textStorage.string as NSString).substringWithRange(range)
print(strSub)
}
}
for range in urlRange ?? [] {
if NSLocationInRange(index, range) {
let strSub = (textStorage.string as NSString).substringWithRange(range)
NSNotificationCenter.defaultCenter().postNotificationName("webView", object: self, userInfo: ["urlString":strSub])
}
}
}
}
extension ZYLabel {
var atRange:[NSRange]? {
let pattern = "@[\u{4e00}-\u{9fa5}]{0,}"
guard let regx = try? NSRegularExpression(pattern: pattern, options: []) else {
return nil
}
let matchs = regx.matchesInString(textStorage.string, options: [], range: NSRange(location: 0,length: textStorage.length))
var ranges = [NSRange]()
for match in matchs {
ranges.append(match.rangeAtIndex(0))
}
return ranges
}
var jingRange:[NSRange]? {
let pattern = "#[\u{4e00}-\u{9fa5}]{0,}#"
guard let regx = try? NSRegularExpression(pattern: pattern, options: []) else {
return nil
}
let matchs = regx.matchesInString(textStorage.string, options: [], range: NSRange(location: 0,length: textStorage.length))
var ranges = [NSRange]()
for match in matchs {
ranges.append(match.rangeAtIndex(0))
}
return ranges
}
var urlRange:[NSRange]? {
let pattern = "((http[s]{0,1}|ftp)://[a-zA-Z0-9\\.\\-]+\\.([a-zA-Z]{2,4})(:\\d+)?(/[a-zA-Z0-9\\.\\-~!@#$%^&*+?:[a-zA-Z0-9_/=<>]]*)?)|(www.[a-zA-Z0-9\\.\\-]+\\.([a-zA-Z]{2,4})(:\\d+)?(/[a-zA-Z0-9\\.\\-~!@#$%^&*+?:_/=<>]*)?)"
guard let regx = try? NSRegularExpression(pattern: pattern, options: []) else {
return nil
}
let matchs = regx.matchesInString(textStorage.string, options: [], range: NSRange(location: 0,length: textStorage.length))
var ranges = [NSRange]()
for match in matchs {
ranges.append(match.rangeAtIndex(0))
}
return ranges
}
}