iostext添加点击事件_iOS给UILabel添加点击事件
前言:筆者最近需要實現(xiàn)給UILabel中的鏈接添加點擊事件的功能。使用so.com查了下,發(fā)現(xiàn)TTTAttributedLabel的封裝程度比較好。整理了TTTAttributedLabel的基本使用,并部分實現(xiàn)了。
TTTAttributedLabel的基本使用
把TTTAttributedLabel.h及TTTAttributedLabel.m放到項目中
遵守TTTAttributedLabelDelegate協(xié)議
// 遵守TTTAttributedLabelDelegate協(xié)議
@interface ViewController ()
復(fù)制代碼
創(chuàng)建TTTAttributedLabel實例及相應(yīng)配置
創(chuàng)建TTTAttributedLabel實例,添加相應(yīng)的配置。
- (void)setupTTTAttributedLabel {
TTTAttributedLabel *attriLabel = [[TTTAttributedLabel alloc] initWithFrame:CGRectZero];
attriLabel.font = [UIFont systemFontOfSize:32.0];
attriLabel.numberOfLines = 0;
// Automatically detect links when the label text is subsequently changed
attriLabel.enabledTextCheckingTypes = NSTextCheckingTypeLink;
// Delegate methods are called when the user taps on a link (see `TTTAttributedLabelDelegate` protocol)
attriLabel.delegate = self;
// Repository URL will be automatically detected and linked
attriLabel.text = @"Fork me on GitHub! (https://github.com/mattt/TTTAttributedLabel/)";
NSRange range = [attriLabel.text rangeOfString:@"me"];
// Embedding a custom link in a substring
[attriLabel addLinkToURL:[NSURL URLWithString:@"http://github.com/mattt/"] withRange:range];
[self.view addSubview:attriLabel];
attriLabel.frame = CGRectMake(20.0, 100.0, 300.0, 200.0);
}
實現(xiàn)TTTAttributedLabelDelegate代理方法
在如下代理方法中查看當(dāng)前點擊的鏈接。
//! 實現(xiàn)代理方法
- (void)attributedLabel:(TTTAttributedLabel *)label didSelectLinkWithURL:(NSURL *)url {
NSLog(@"url信息:%@", url);
}
TTTAttributedLabel部分實現(xiàn)
設(shè)置attriLabel.text = @"Fork me on GitHub! (https://github.com/mattt/TTTAttributedLabel/)";查看了TTTAttributedLabel的大概實現(xiàn)流程。
設(shè)置TTTAttributedLabel用戶交互可用。
self.userInteractionEnabled = YES;
TTTAttributedLabel鏈接指定了替代鏈接樣式
TTTAttributedLabel為鏈接指定了替代鏈接樣式為藍(lán)色和帶下劃線。
相關(guān)代碼為:
NSMutableDictionary *mutableLinkAttributes = [NSMutableDictionary dictionary];
[mutableLinkAttributes setObject:[NSNumber numberWithBool:YES] forKey:(NSString *)kCTUnderlineStyleAttributeName];
if ([NSMutableParagraphStyle class]) {
[mutableLinkAttributes setObject:[UIColor blueColor] forKey:(NSString *)kCTForegroundColorAttributeName];
} else {
[mutableLinkAttributes setObject:(__bridge id)[[UIColor blueColor] CGColor] forKey:(NSString *)kCTForegroundColorAttributeName];
}
self.linkAttributes = [NSDictionary dictionaryWithDictionary:mutableLinkAttributes];
使用NSDataDetector檢測label.text中的鏈接
NSArray *results = [dataDetector matchesInString:[(NSAttributedString *)text string] options:0 range:NSMakeRange(0, [(NSAttributedString *)text length])];
NSArray *類型的results副本中會有l(wèi)abel中文本的鏈接信息。
如
<__nsarraym>(
{20, 44}{https://github.com/mattt/TTTAttributedLabel/}
)
// label.text中的URL
(lldb) po ((NSLinkCheckingResult *)[results lastObject]).URL
https://github.com/mattt/TTTAttributedLabel/
// label.text中的URL 的range
(lldb) po ((NSLinkCheckingResult *)[results lastObject]).range
location=20, length=44
“自動檢測”鏈接
當(dāng)我們設(shè)置了attriLabel.text = @"Fork me on GitHub! (https://github.com/mattt/TTTAttributedLabel/)";時,會發(fā)現(xiàn)https://github.com/mattt/TTTAttributedLabel/自動轉(zhuǎn)換鏈接形式。自動檢測出label.text中的文本中有url信息是依次在- (NSArray *)addLinksWithTextCheckingResults:(NSArray *)results attributes:(NSDictionary *)attributes及- (void)addLinks:(NSArray *)links的實現(xiàn)中做的處理。
首先通過在- (NSArray *)addLinksWithTextCheckingResults:(NSArray *)results attributes:(NSDictionary *)attributes方法中封裝鏈接文本屬性信息媒介TTTAttributedLabelLink。
再通過在- (void)addLinks:(NSArray *)links方法中根據(jù)TTTAttributedLabelLink傳遞過來的文本屬性及URL位置信息,設(shè)置label.attributedText以達(dá)到能夠自動檢測出label.text中url的目的。
另外我們自行添加addLinkToURl
- (void)addLinks:(NSArray *)links {
...
self.attributedText = mutableAttributedString;
...
}
添加鏈接到指定range
以[attriLabel addLinkToURL:[NSURL URLWithString:@"http://github.com/mattt/"] withRange:range];為例。可以發(fā)現(xiàn)TTTAttributedLabel內(nèi)部實現(xiàn)是
[self addLinkWithTextCheckingResult:[NSTextCheckingResult linkCheckingResultWithRange:range URL:url]];直到
[self addLinkWithTextCheckingResult:result attributes:self.linkAttributes];就和上述的“自動檢測”鏈接的內(nèi)容是一樣的。
點擊標(biāo)簽的鏈接文字后,查找到對應(yīng)url
這部分內(nèi)容主要分為touchesBegan方法中查找點擊的位置的鏈接,touchesMoved方法中比對觸摸到標(biāo)簽上的位置移動后,當(dāng)前位置的鏈接和touchesBegan方法中找到的鏈接是否一樣,最后在touchesEnded中把點擊的鏈接以為塊和代理的方式傳遞出去。
下邊簡單說明下筆者查看touchesBegan方法中查找點擊鏈接的內(nèi)容。
獲取到當(dāng)前點擊的點
[touch locationInView:self]
在- (TTTAttributedLabelLink *)linkAtPoint:(CGPoint)point方法中獲取到當(dāng)前點鏈接
首先在- (CFIndex)characterIndexAtPoint:(CGPoint)p方法中找到點擊的位置的字符的索引,然后通過- (TTTAttributedLabelLink *)linkAtCharacterIndex:(CFIndex)idx方法中找到對應(yīng)的字符的索引的TTTAttributedLabelLink實例(其中包含當(dāng)前點擊點的鏈接信息)
[self linkAtPoint:[touch locationInView:self]];
TTTAttributedLabelLink *result = [self linkAtCharacterIndex:[self characterIndexAtPoint:point]];
獲取到當(dāng)前點擊位置的字符的索引
筆者感覺其中難理解的地方為獲取到當(dāng)前點擊位置的字符的索引。相關(guān)內(nèi)容如下:
將當(dāng)前點的坐標(biāo)轉(zhuǎn)換為對應(yīng)的UILabel中的文字坐標(biāo)轉(zhuǎn)換為針對于UILabel自身坐標(biāo)系的點坐標(biāo);
p = CGPointMake(p.x - textRect.origin.x, p.y - textRect.origin.y);
另一個是把iOS做左上角為原點坐標(biāo)轉(zhuǎn)換為CT坐標(biāo)系的左下角為原點坐標(biāo)的調(diào)整。
p = CGPointMake(p.x, textRect.size.height - p.y);
根據(jù)當(dāng)前標(biāo)簽相對自身坐標(biāo)系frame和屬性鏈接創(chuàng)建CT坐標(biāo)系所需的frame
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, textRect);
CTFrameRef frame = CTFramesetterCreateFrame([self framesetter], CFRangeMake(0, (CFIndex)[self.attributedText length]), path, NULL);
確定UILabel當(dāng)前在CT坐標(biāo)系顯示占用的行數(shù)CFArrayGetCount(lines)
NSInteger numberOfLines = self.numberOfLines > 0 ? MIN(self.numberOfLines, CFArrayGetCount(lines)) : CFArrayGetCount(lines);
遍歷CT坐標(biāo)中文字的每一行,找到當(dāng)前點擊點所在的行,計算出點擊點相對于當(dāng)前行的坐標(biāo),并計算出當(dāng)前索引。
CGPoint relativePoint = CGPointMake(p.x - lineOrigin.x, p.y - lineOrigin.y);
idx = CTLineGetStringIndexForPosition(line, relativePoint);
其中還有ascent(字形最高點到baseline的推薦距離)和下降(字形最低點到baseline的推薦距離)相關(guān)的內(nèi)容等。筆者不了解,有興趣的話,可以查看CoreText相關(guān)內(nèi)容,如深入理解Core Text投放引擎
CFIndex idx = NSNotFound;
CGPoint lineOrigins[numberOfLines];
CTFrameGetLineOrigins(frame, CFRangeMake(0, numberOfLines), lineOrigins);
for (CFIndex lineIndex = 0; lineIndex < numberOfLines; lineIndex++) {
CGPoint lineOrigin = lineOrigins[lineIndex];
CTLineRef line = CFArrayGetValueAtIndex(lines, lineIndex);
// Get bounding information of line
CGFloat ascent = 0.0f, descent = 0.0f, leading = 0.0f;
CGFloat width = (CGFloat)CTLineGetTypographicBounds(line, &ascent, &descent, &leading);
CGFloat yMin = (CGFloat)floor(lineOrigin.y - descent);
CGFloat yMax = (CGFloat)ceil(lineOrigin.y + ascent);
// Apply penOffset using flushFactor for horizontal alignment to set lineOrigin since this is the horizontal offset from drawFramesetter
CGFloat flushFactor = TTTFlushFactorForTextAlignment(self.textAlignment);
CGFloat penOffset = (CGFloat)CTLineGetPenOffsetForFlush(line, flushFactor, textRect.size.width);
lineOrigin.x = penOffset;
// Check if we've already passed the line
if (p.y > yMax) {
break;
}
// Check if the point is within this line vertically
if (p.y >= yMin) {
// Check if the point is within this line horizontally
if (p.x >= lineOrigin.x && p.x <= lineOrigin.x + width) {
// Convert CT coordinates to line-relative coordinates
CGPoint relativePoint = CGPointMake(p.x - lineOrigin.x, p.y - lineOrigin.y);
idx = CTLineGetStringIndexForPosition(line, relativePoint);
break;
}
}
}
復(fù)制代碼
總結(jié)
以上是生活随笔為你收集整理的iostext添加点击事件_iOS给UILabel添加点击事件的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 上海欢乐谷营业时间
- 下一篇: 微信小程序 python接口_微信小程序