項目中有一個需求就是實現一段文字中有幾個特殊的字符可以有下劃線,并且可以進行點擊。
首先可以實現下劃線效果,首先想到的是UILabel和UITextView控件的 NSMutableAttributedString 屬性,考慮到可能會有點擊事件效果的實現,這里選擇UITextView控件,因為UITextView有一個功能就是能通過NSRange獲得文字的相應的Frame。
最終實現這種效果,帶下劃線的可以點擊,點擊可以設置背景顏色,也可以不設置背景顏色,可以設置下換線以及下劃線上面文字的顏色。
實現效果.png
1、首先創建UITextView類
創建UITextView.png
2、ClickTextView類中聲明點擊回調的block,這里回調用block進行回調
/** 點擊回調的block */
typedef void(^clickTextViewPartBlock)(NSString *clickText);
3、介紹下主要的實現方法
1>、這個方法主要是將下劃線對用的文字的frame,文字內容,點擊效果背景顏色存儲起來,以供點擊的時候查詢
/**
* 設置textView的部分為下劃線,并且使之可以點擊
*
* @param underlineTextRange 需要下劃線的文字范圍,如果NSRange范圍超出總的內容,將過濾掉
* @param color 下劃線的顏色,以及下劃線上面文字的顏色
* @param coverColor 是否有點擊的背景,如果設置相關顏色的話,將會有點擊效果,如果為nil將沒有點擊效果
* @param block 點擊文字的時候的回調
*/
- (void)setUnderlineTextWithRange:(NSRange)underlineTextRange withUnderlineColor:(UIColor *)color withClickCoverColor:(UIColor *)coverColor withBlock:(clickTextViewPartBlock)block
{
if (self.text.length < underlineTextRange.location+underlineTextRange.length) {
return;
}
// 設置下劃線
[self.content addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithInteger:NSUnderlineStyleSingle] range:underlineTextRange];
//設置文字顏色
if (color) {
[self.content addAttribute:NSForegroundColorAttributeName value:color range:underlineTextRange];
}
self.attributedText = self.content;
// 設置下劃線文字的點擊事件
// self.selectedRange 影響 self.selectedTextRange
self.selectedRange = underlineTextRange;
// 獲取選中范圍內的矩形框
NSArray *selectionRects = [self selectionRectsForRange:self.selectedTextRange];
// 清空選中范圍
self.selectedRange = NSMakeRange(0, 0);
// 可能會點擊的范圍的數組
NSMutableArray *selectedArray = [[NSMutableArray alloc] init];
for (UITextSelectionRect *selectionRect in selectionRects) {
CGRect rect = selectionRect.rect;
if (rect.size.width == 0 || rect.size.height == 0) {
continue;
}
// 將有用的信息打包<存放到字典中>存儲到數組中
NSMutableDictionary *dic = [[NSMutableDictionary alloc] init];
// 存儲文字對應的frame,一段文字可能會有兩個甚至多個frame,考慮到文字換行問題
[dic setObject:[NSValue valueWithCGRect:rect] forKey:@"rect"];
// 存儲下劃線對應的文字
[dic setObject:[self.text substringWithRange:underlineTextRange] forKey:@"content"];
// 存儲相應的回調的block
[dic setObject:block forKey:@"block"];
// 存儲對應的點擊效果背景顏色
[dic setValue:coverColor forKey:@"coverColor"];
[selectedArray addObject:dic];
}
// 將可能點擊的范圍的數組存儲到總的數組中
[self.rectsArray addObject:selectedArray];
}
2>、通過一個點擊的點,去查找有沒有點在下劃線對用的文字范圍內,并且返回之前打包<存儲的字典>的數據模型
- (NSArray *)touchingSpecialWithPoint:(CGPoint)point
{
// 從所有的特殊的范圍中找到點擊的那個點
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>、通過touchesBegan的方法,獲取點擊的點,并且去查詢相關數據模型,并且根據參數是不是展示相應的點擊效果,并且通過blcok進行回調
// 點擊textView的 touchesBegan 方法
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
// 獲取觸摸對象
UITouch *touch = [touches anyObject];
// 觸摸點
CGPoint point = [touch locationInView:self];
// 通過一個觸摸點,查詢點擊的是不是在下劃線對應的文字的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) {
// 如果說有點擊效果的話,加個延時,展示下點擊效果,如果沒有點擊效果的話,直接回調
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>、點擊結束的時候取消點擊效果,也就是刪除點擊的時候創建的view
/** 點擊結束的時候 */
- (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];
}
}
});
}
/**
* 取消點擊的時候,清除相關的陰影
*/
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
for (UIView *subView in self.subviews) {
if (subView.tag == kCoverViewTag) {
[subView removeFromSuperview];
}
}
}
5、在ViewController中進行測試
ClickTextView *clickTextView = [[ClickTextView alloc] initWithFrame:CGRectMake(50, 50, 300, 300)];
[self.view addSubview:clickTextView];
// 方便測試,設置textView的邊框已經背景
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承諾書都差不多歲尺布斗粟CBD死UC收不到催上半場低俗";
// 設置文字
clickTextView.text = content;
// 設置期中的一段文字有下劃線,下劃線的顏色為藍色,點擊下劃線文字有相關的點擊效果
NSRange range1 = [content rangeOfString:@"承諾書都差"];
[clickTextView setUnderlineTextWithRange:range1 withUnderlineColor:[UIColor blueColor] withClickCoverColor:[UIColor greenColor] withBlock:^(NSString *clickText) {
NSLog(@"clickText = %@",clickText);
}];
// 設置期中的一段文字有下劃線,下劃線的顏色沒有設置,點擊下劃線文字沒有點擊效果
NSRange range2 = [content rangeOfString:@"不到催上半場低俗"];
[clickTextView setUnderlineTextWithRange:range2 withUnderlineColor:nil withClickCoverColor:nil withBlock:^(NSString *clickText) {
NSLog(@"clickText = %@",clickText);
}];
如有失誤請各位路過大神即時指點,或有更好的做法,也請指點一二。
詳情Demo可參考