前言:笔者最近需要实现给UILabel中的链接添加点击事件的功能。使用so.com查了下,发现TTTAttributedLabel的封装程度比较好。整理了TTTAttributedLabel的基本使用,并部分实现了。

TTTAttributedLabel的基本使用

把TTTAttributedLabel.h及TTTAttributedLabel.m放到项目中

遵守TTTAttributedLabelDelegate协议

// 遵守TTTAttributedLabelDelegate协议

@interface ViewController ()

复制代码

创建TTTAttributedLabel实例及相应配置

创建TTTAttributedLabel实例,添加相应的配置。

- (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);

}

实现TTTAttributedLabelDelegate代理方法

在如下代理方法中查看当前点击的链接。

//! 实现代理方法

- (void)attributedLabel:(TTTAttributedLabel *)label didSelectLinkWithURL:(NSURL *)url {

NSLog(@"url信息:%@", url);

}

TTTAttributedLabel部分实现

设置attriLabel.text = @"Fork me on GitHub! (https://github.com/mattt/TTTAttributedLabel/)";查看了TTTAttributedLabel的大概实现流程。

设置TTTAttributedLabel用户交互可用。

self.userInteractionEnabled = YES;

TTTAttributedLabel链接指定了替代链接样式

TTTAttributedLabel为链接指定了替代链接样式为蓝色和带下划线。

相关代码为:

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副本中会有label中文本的链接信息。

<__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

“自动检测”链接

当我们设置了attriLabel.text = @"Fork me on GitHub! (https://github.com/mattt/TTTAttributedLabel/)";时,会发现https://github.com/mattt/TTTAttributedLabel/自动转换链接形式。自动检测出label.text中的文本中有url信息是依次在- (NSArray *)addLinksWithTextCheckingResults:(NSArray *)results attributes:(NSDictionary *)attributes及- (void)addLinks:(NSArray *)links的实现中做的处理。

首先通过在- (NSArray *)addLinksWithTextCheckingResults:(NSArray *)results attributes:(NSDictionary *)attributes方法中封装链接文本属性信息媒介TTTAttributedLabelLink。

再通过在- (void)addLinks:(NSArray *)links方法中根据TTTAttributedLabelLink传递过来的文本属性及URL位置信息,设置label.attributedText以达到能够自动检测出label.text中url的目的。

另外我们自行添加addLinkToURl

- (void)addLinks:(NSArray *)links {

...

self.attributedText = mutableAttributedString;

...

}

添加链接到指定range

以[attriLabel addLinkToURL:[NSURL URLWithString:@"http://github.com/mattt/"] withRange:range];为例。可以发现TTTAttributedLabel内部实现是

[self addLinkWithTextCheckingResult:[NSTextCheckingResult linkCheckingResultWithRange:range URL:url]];直到

[self addLinkWithTextCheckingResult:result attributes:self.linkAttributes];就和上述的“自动检测”链接的内容是一样的。

点击标签的链接文字后,查找到对应url

这部分内容主要分为touchesBegan方法中查找点击的位置的链接,touchesMoved方法中比对触摸到标签上的位置移动后,当前位置的链接和touchesBegan方法中找到的链接是否一样,最后在touchesEnded中把点击的链接以为块和代理的方式传递出去。

下边简单说明下笔者查看touchesBegan方法中查找点击链接的内容。

获取到当前点击的点

[touch locationInView:self]

在- (TTTAttributedLabelLink *)linkAtPoint:(CGPoint)point方法中获取到当前点链接

首先在- (CFIndex)characterIndexAtPoint:(CGPoint)p方法中找到点击的位置的字符的索引,然后通过- (TTTAttributedLabelLink *)linkAtCharacterIndex:(CFIndex)idx方法中找到对应的字符的索引的TTTAttributedLabelLink实例(其中包含当前点击点的链接信息)

[self linkAtPoint:[touch locationInView:self]];

TTTAttributedLabelLink *result = [self linkAtCharacterIndex:[self characterIndexAtPoint:point]];

获取到当前点击位置的字符的索引

笔者感觉其中难理解的地方为获取到当前点击位置的字符的索引。相关内容如下:

将当前点的坐标转换为对应的UILabel中的文字坐标转换为针对于UILabel自身坐标系的点坐标;

p = CGPointMake(p.x - textRect.origin.x, p.y - textRect.origin.y);

另一个是把iOS做左上角为原点坐标转换为CT坐标系的左下角为原点坐标的调整。

p = CGPointMake(p.x, textRect.size.height - p.y);

根据当前标签相对自身坐标系frame和属性链接创建CT坐标系所需的frame

CGMutablePathRef path = CGPathCreateMutable();

CGPathAddRect(path, NULL, textRect);

CTFrameRef frame = CTFramesetterCreateFrame([self framesetter], CFRangeMake(0, (CFIndex)[self.attributedText length]), path, NULL);

确定UILabel当前在CT坐标系显示占用的行数CFArrayGetCount(lines)

NSInteger numberOfLines = self.numberOfLines > 0 ? MIN(self.numberOfLines, CFArrayGetCount(lines)) : CFArrayGetCount(lines);

遍历CT坐标中文字的每一行,找到当前点击点所在的行,计算出点击点相对于当前行的坐标,并计算出当前索引。

CGPoint relativePoint = CGPointMake(p.x - lineOrigin.x, p.y - lineOrigin.y);

idx = CTLineGetStringIndexForPosition(line, relativePoint);

其中还有ascent(字形最高点到baseline的推荐距离)和下降(字形最低点到baseline的推荐距离)相关的内容等。笔者不了解,有兴趣的话,可以查看CoreText相关内容,如深入理解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;

}

}

}

复制代码

iostext添加点击事件_iOS给UILabel添加点击事件相关推荐

  1. 154在屏幕中绘图时设置透明度(扩展知识:为图片视图添加点击手势识别器,来实现点击事件操作)...

    一张图片,通过混合模式绘制后,能得到不同效果的图片. 这里的示例仅是测试效果:实际上可以通过不同程度的混合模式绘制,来得到符合需求的效果. 效果如下: ViewController.h 1 #impo ...

  2. android高德marker添加点击,高德地图上添加marker,给每一个marker添加点击事件。...

    高德地图上添加marker,给每一个marker添加点击事件. 高德地图上添加marker,给每一个marker添加点击事件.javascript var watch = [] $.ajax({ ty ...

  3. html点击除某个元素之外的元素的事件添加技巧

    可以利用css中的z-index属性来完成,先在页面添加一个div,设置这个div的属性为:宽高都为100%,透明属性opacity为0,绝对定位为top:0,left:0,暂且称这个div为a,添加 ...

  4. IOS 为UILabel添加长按复制功能

    IOS 为UILabel添加长按复制功能 在iOS中下面三个控件,自身就有复制-粘贴的功能: 1.UITextView 2.UITextField 3.UIWebView UIKit framewor ...

  5. UILabel添加图片之富文本的简单应用

    若想对UILabel添加图片,那么就需要使用NSMutableAttributedString来定义 先定义一个普通的label UILabel *lab = [[UILabel alloc]init ...

  6. android 模拟点击localinstrumentation,Android Instrumentation模拟鼠标点击事件

    看了几遍网上的博客一直没有 模拟出鼠标点击事件和按钮事件,后来抱着试试态度再重试的时候终于有所斩获.下面把具体的情况记录一下: 首先我们必须了解类 Instrumentation: Instrumen ...

  7. android友盟统计按钮点击次数,友盟统计按钮点击事件

    让用户数据动起来--给app增加运营 一.初识友盟 友盟大家都听说过,在给app集成友盟之前对友盟的认识没有那么深刻.用了友盟之后,才发现友盟很强大. 集成友盟能够获取那些数据呢? 用户的基本信息:比 ...

  8. 地图绘制边界。高德。PPMAP。 鼠标点击经纬度坐标 。地图图标点点击弹窗窗口。地图图标点点击事件。

    边界: == 第一种:绘制边界. 通过绘制多边形的API来绘制边界. 高德API:多边形 Polygon. 矢量图形-覆盖物-教程-地图 JS API | 高德地图API 将关键的边界轮廓 经纬度坐标 ...

  9. java 按钮 事件_Java给按钮添加事件

    展开全部 赞一个, 提前学习, 做好预先 , 是个好习惯.java图形界面主要62616964757a686964616fe4b893e5b19e31333365636666有AWT, SWING, ...

最新文章

  1. NOIP2018TG 初赛复习
  2. 平衡二叉树-AVL c/c++代码实现
  3. HDU.3177Crixalis's Equipment(贪心)
  4. .net 连接mysql的字符串_asp.net连接数据库字符串
  5. vue + element 顶部二级菜单_揭秘vue/react组件库中5个quot;作者不造的轮子quot;
  6. 关于 SAP Spartacus 支持不同的环境配置部署到 SAP Commerce Cloud 上的讨论
  7. 拉格朗日插值法(Lagrange)
  8. 服务器云平台 系统,服务器云平台 系统
  9. WORD表格中文字显示不完整怎么办?
  10. 基于JAVA+SpringMVC+Mybatis+MYSQL的考勤管理系统
  11. 用python统计文章中单词出现的频次
  12. java获取当前年月日历_转:JavaCalendar获取年、月、日、时间
  13. jupyter快捷键、markdown语法及markdown的算式语法
  14. 【转】Eclipse下支持编写HTML/JS/CSS/JSP页面的自动提示
  15. louvain算法python_python – 如何在igraph中运行louvain社区检测算法?
  16. Sql代码美化工具:Sql Pretty Printer for SSMS V3.6.1
  17. Python实现快速查找文件
  18. 如何寻找logo创意灵感?推荐这8个设计灵感网站
  19. 非宁静无以致远,借以静化心灵
  20. 数模转换DAC-TLC5615的说明

热门文章

  1. C++ 笔记(36)—— std::cout 输出保留小数位数
  2. Ubuntu20.04安装zabbix以及Cannot create the configuration file解决
  3. debian10 dhcp简单配置
  4. 【J2SE】学习基础
  5. python中break和continue的区别
  6. LeetCode简单题之下载插件
  7. 合肥工业大学—SQL Server数据库实验一:数据库的创建和删除
  8. CloudHub概述
  9. 使用IDEA开发Servlet程序
  10. 红旗linuxcentos_用红旗Linux 11的体验报告,附使用红旗Linux 11截图