項(xiàng)目中有一個(gè)需求就是實(shí)現(xiàn)一段文字中有幾個(gè)特殊的字符可以有下劃線,并且可以進(jìn)行點(diǎn)擊般哼。
首先可以實(shí)現(xiàn)下劃線效果吴汪,首先想到的是UILabel和UITextView控件的 NSMutableAttributedString 屬性,考慮到可能會(huì)有點(diǎn)擊事件效果的實(shí)現(xiàn)蒸眠,這里選擇UITextView控件,因?yàn)閁ITextView有一個(gè)功能就是能通過(guò)NSRange獲得文字的相應(yīng)的Frame漾橙。
最終實(shí)現(xiàn)這種效果,帶下劃線的可以點(diǎn)擊楞卡,點(diǎn)擊可以設(shè)置背景顏色霜运,也可以不設(shè)置背景顏色,可以設(shè)置下?lián)Q線以及下劃線上面文字的顏色蒋腮。
1淘捡、首先創(chuàng)建UITextView類
2、ClickTextView類中聲明點(diǎn)擊回調(diào)的block池摧,這里回調(diào)用block進(jìn)行回調(diào)
/** 點(diǎn)擊回調(diào)的block */
typedef void(^clickTextViewPartBlock)(NSString *clickText);
3焦除、介紹下主要的實(shí)現(xiàn)方法
1>、這個(gè)方法主要是將下劃線對(duì)用的文字的frame作彤,文字內(nèi)容膘魄,點(diǎn)擊效果背景顏色存儲(chǔ)起來(lái),以供點(diǎn)擊的時(shí)候查詢
/**
* 設(shè)置textView的部分為下劃線竭讳,并且使之可以點(diǎn)擊
*
* @param underlineTextRange 需要下劃線的文字范圍创葡,如果NSRange范圍超出總的內(nèi)容,將過(guò)濾掉
* @param color 下劃線的顏色绢慢,以及下劃線上面文字的顏色
* @param coverColor 是否有點(diǎn)擊的背景灿渴,如果設(shè)置相關(guān)顏色的話,將會(huì)有點(diǎn)擊效果胰舆,如果為nil將沒(méi)有點(diǎn)擊效果
* @param block 點(diǎn)擊文字的時(shí)候的回調(diào)
*/
- (void)setUnderlineTextWithRange:(NSRange)underlineTextRange withUnderlineColor:(UIColor *)color withClickCoverColor:(UIColor *)coverColor withBlock:(clickTextViewPartBlock)block
{
if (self.text.length < underlineTextRange.location+underlineTextRange.length) {
return;
}
// 設(shè)置下劃線
[self.content addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithInteger:NSUnderlineStyleSingle] range:underlineTextRange];
//設(shè)置文字顏色
if (color) {
[self.content addAttribute:NSForegroundColorAttributeName value:color range:underlineTextRange];
}
self.attributedText = self.content;
// 設(shè)置下劃線文字的點(diǎn)擊事件
// self.selectedRange 影響 self.selectedTextRange
self.selectedRange = underlineTextRange;
// 獲取選中范圍內(nèi)的矩形框
NSArray *selectionRects = [self selectionRectsForRange:self.selectedTextRange];
// 清空選中范圍
self.selectedRange = NSMakeRange(0, 0);
// 可能會(huì)點(diǎn)擊的范圍的數(shù)組
NSMutableArray *selectedArray = [[NSMutableArray alloc] init];
for (UITextSelectionRect *selectionRect in selectionRects) {
CGRect rect = selectionRect.rect;
if (rect.size.width == 0 || rect.size.height == 0) {
continue;
}
// 將有用的信息打包<存放到字典中>存儲(chǔ)到數(shù)組中
NSMutableDictionary *dic = [[NSMutableDictionary alloc] init];
// 存儲(chǔ)文字對(duì)應(yīng)的frame骚露,一段文字可能會(huì)有兩個(gè)甚至多個(gè)frame,考慮到文字換行問(wèn)題
[dic setObject:[NSValue valueWithCGRect:rect] forKey:@"rect"];
// 存儲(chǔ)下劃線對(duì)應(yīng)的文字
[dic setObject:[self.text substringWithRange:underlineTextRange] forKey:@"content"];
// 存儲(chǔ)相應(yīng)的回調(diào)的block
[dic setObject:block forKey:@"block"];
// 存儲(chǔ)對(duì)應(yīng)的點(diǎn)擊效果背景顏色
[dic setValue:coverColor forKey:@"coverColor"];
[selectedArray addObject:dic];
}
// 將可能點(diǎn)擊的范圍的數(shù)組存儲(chǔ)到總的數(shù)組中
[self.rectsArray addObject:selectedArray];
}
2>思瘟、通過(guò)一個(gè)點(diǎn)擊的點(diǎn)荸百,去查找有沒(méi)有點(diǎn)在下劃線對(duì)用的文字范圍內(nèi),并且返回之前打包<存儲(chǔ)的字典>的數(shù)據(jù)模型
- (NSArray *)touchingSpecialWithPoint:(CGPoint)point
{
// 從所有的特殊的范圍中找到點(diǎn)擊的那個(gè)點(diǎn)
for (NSArray *selecedArray in self.rectsArray) {
for (NSDictionary *dic in selecedArray) {
CGRect myRect = [dic[@"rect"] CGRectValue];
if(CGRectContainsPoint(myRect, point) ){
return selecedArray;
}
}
}
return nil;
}
3>滨攻、通過(guò)touchesBegan的方法够话,獲取點(diǎn)擊的點(diǎn)蓝翰,并且去查詢相關(guān)數(shù)據(jù)模型,并且根據(jù)參數(shù)是不是展示相應(yīng)的點(diǎn)擊效果女嘲,并且通過(guò)blcok進(jìn)行回調(diào)
// 點(diǎn)擊textView的 touchesBegan 方法
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
// 獲取觸摸對(duì)象
UITouch *touch = [touches anyObject];
// 觸摸點(diǎn)
CGPoint point = [touch locationInView:self];
// 通過(guò)一個(gè)觸摸點(diǎn)畜份,查詢點(diǎn)擊的是不是在下劃線對(duì)應(yīng)的文字的frame
NSArray *selectedArray = [self touchingSpecialWithPoint:point];
for (NSDictionary *dic in selectedArray) {
if(dic && dic[@"coverColor"]){
UIView *cover = [[UIView alloc] init];
cover.backgroundColor = dic[@"coverColor"];
cover.frame = [dic[@"rect"] CGRectValue];
cover.layer.cornerRadius = 5;
cover.tag = kCoverViewTag;
[self insertSubview:cover atIndex:0];
}
}
if (selectedArray.count) {
// 如果說(shuō)有點(diǎn)擊效果的話,加個(gè)延時(shí)欣尼,展示下點(diǎn)擊效果,如果沒(méi)有點(diǎn)擊效果的話爆雹,直接回調(diào)
NSDictionary *dic = [selectedArray firstObject];
clickTextViewPartBlock block = dic[@"block"];
if (dic[@"coverColor"]) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
block(dic[@"content"]);
});
}else{
block(dic[@"content"]);
}
}
}
4>、點(diǎn)擊結(jié)束的時(shí)候取消點(diǎn)擊效果愕鼓,也就是刪除點(diǎn)擊的時(shí)候創(chuàng)建的view
/** 點(diǎn)擊結(jié)束的時(shí)候 */
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
for (UIView *subView in self.subviews) {
if (subView.tag == kCoverViewTag) {
[subView removeFromSuperview];
}
}
});
}
/**
* 取消點(diǎn)擊的時(shí)候,清除相關(guān)的陰影
*/
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
for (UIView *subView in self.subviews) {
if (subView.tag == kCoverViewTag) {
[subView removeFromSuperview];
}
}
}
5钙态、在ViewController中進(jìn)行測(cè)試
ClickTextView *clickTextView = [[ClickTextView alloc] initWithFrame:CGRectMake(50, 50, 300, 300)];
[self.view addSubview:clickTextView];
// 方便測(cè)試,設(shè)置textView的邊框已經(jīng)背景
clickTextView.backgroundColor = [UIColor cyanColor];
clickTextView.layer.borderWidth = 1;
clickTextView.layer.borderColor = [UIColor redColor].CGColor;
clickTextView.font = [UIFont systemFontOfSize:30];
//clickTextView.textColor = [UIColor redColor];
NSString *content = @"1234567890承諾書(shū)都差不多歲尺布斗粟CBD死UC收不到催上半場(chǎng)低俗";
// 設(shè)置文字
clickTextView.text = content;
// 設(shè)置期中的一段文字有下劃線菇晃,下劃線的顏色為藍(lán)色册倒,點(diǎn)擊下劃線文字有相關(guān)的點(diǎn)擊效果
NSRange range1 = [content rangeOfString:@"承諾書(shū)都差"];
[clickTextView setUnderlineTextWithRange:range1 withUnderlineColor:[UIColor blueColor] withClickCoverColor:[UIColor greenColor] withBlock:^(NSString *clickText) {
NSLog(@"clickText = %@",clickText);
}];
// 設(shè)置期中的一段文字有下劃線,下劃線的顏色沒(méi)有設(shè)置磺送,點(diǎn)擊下劃線文字沒(méi)有點(diǎn)擊效果
NSRange range2 = [content rangeOfString:@"不到催上半場(chǎng)低俗"];
[clickTextView setUnderlineTextWithRange:range2 withUnderlineColor:nil withClickCoverColor:nil withBlock:^(NSString *clickText) {
NSLog(@"clickText = %@",clickText);
}];
如有失誤請(qǐng)各位路過(guò)大神即時(shí)指點(diǎn)驻子,或有更好的做法,也請(qǐng)指點(diǎn)一二估灿。
詳情Demo可參考
擴(kuò)展:iOS 設(shè)置下劃線與文字之間的距離