iOS實現一段文字中部分有下劃線,并且可以點擊

項目中有一個需求就是實現一段文字中有幾個特殊的字符可以有下劃線,并且可以進行點擊。
首先可以實現下劃線效果,首先想到的是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可參考

擴展:iOS 設置下劃線與文字之間的距離

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Text Kit學習(入門和進階): http://www.cocoachina.com/industry/201...
    F麥子閱讀 4,231評論 1 13
  • 發現 關注 消息 iOS 第三方庫、插件、知名博客總結 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,252評論 4 61
  • 相比以前,更加的喜歡自己,才是最大的夢想,精神的釋放
    alialiali閱讀 149評論 0 0
  • 別后不知君遠近,觸目凄涼多少悶! 漸行漸遠漸無書,水闊魚沉何處問? 武漢·晴 今天陽光微醺,陽光偷偷爬近書桌,溫...
    特別的貓呢閱讀 678評論 0 5
  • 不管別人做了什么,我可以不生氣嗎? 曾經年輕的花姐,一年之中總會有那么幾次情緒失控而生氣,甚至氣到歇斯底里,有時是...
    花姐瞎掰掰閱讀 1,855評論 2 9