UILabel 给指定字符添加点击事件

需要导入CoreText框架

效果图:

  • 日历控件点击2019:


    image.png
  • 点击2019打印的日志:


    image.png

1、给label增加tap手势:

UITapGestureRecognizer *yearTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapYearAction:)];
_montLabel.userInteractionEnabled = YES;
[_montLabel addGestureRecognizer:yearTap];

2、格式化label字符串:

NSString *yearString = [NSString stringWithFormat:@"%ld", [startDate year]];
[self formatDateLabelWithYearString:yearString withAllString:self.montLabel.text];

3、相关代码:

#pragma mark - 格式化日期,并给年份增加点击事件
- (void)formatDateLabelWithYearString:(NSString *)yearString withAllString:(NSString *)allString {
    if (yearString == nil || yearString.length <= 0 || allString == nil || allString.length < yearString.length) {
        return ;
    }
    NSMutableAttributedString *attr = [[NSMutableAttributedString alloc] initWithString:allString];
    NSRange yearRange = [allString rangeOfString:yearString];
    if (yearRange.location == NSNotFound) {
        return ;
    }
    [attr addAttribute:@"YSYearAttributeName" value:yearString range:yearRange];
    [attr addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:yearRange];
    self.montLabel.attributedText = attr;
}

- (void)tapYearAction:(UITapGestureRecognizer *)gesture {
    if (gesture.state == UIGestureRecognizerStateRecognized) {
        CGPoint point = [gesture locationInView:self.montLabel];
        NSDictionary *dic = [self textAttributesAtPoint:point withLabel:self.montLabel];
        for (NSString *attributeName in dic.allKeys) {
            if ([attributeName isEqualToString:@"YSYearAttributeName"]) {
                NSString *pointString = dic[@"YSYearAttributeName"];
                NSLog(@"你点击了 %@ 年", pointString);
            }
        }
    }
}

#pragma mark - UILabel中对应的点pt在UILabel中所有的字体属性(用coreText 实现)
- (NSDictionary*)textAttributesAtPoint:(CGPoint)pt withLabel:(UILabel*)lab{
    // Locate the attributes of the text within the label at the specified point
    NSDictionary* dictionary =nil;
    // First, create a CoreText framesetter
    CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)lab.attributedText);
    CGMutablePathRef framePath =CGPathCreateMutable();
    CGPathAddRect(framePath,NULL,CGRectMake(0,0, lab.frame.size.width, lab.frame.size.height));
    // Get the frame that will do the rendering.
    CFRange currentRange =CFRangeMake(0,0);
    CTFrameRef frameRef =CTFramesetterCreateFrame(framesetter, currentRange, framePath,NULL);
    CGPathRelease(framePath);
    // Get each of the typeset lines
    NSArray*lines = (__bridge id)CTFrameGetLines(frameRef);
    CFIndex linesCount = [lines count];
    CGPoint *lineOrigins = (CGPoint *)malloc(sizeof(CGPoint) * linesCount);
    CTFrameGetLineOrigins(frameRef,CFRangeMake(0, linesCount), lineOrigins);
    CTLineRef line = NULL;
    CGPoint lineOrigin = CGPointZero;
    // Correct each of the typeset lines (which have origin (0,0)) to the correct orientation (typesetting offsets from the bottom of the frame)
    CGFloat bottom = lab.frame.size.height;
    for (CFIndex i = 0; i < linesCount; ++i) {
        lineOrigins[i].y = lab.frame.size.height- lineOrigins[i].y;
        bottom = lineOrigins[i].y;
    }
    // Offset the touch point by the amount of space between the top of the label frame and the text
    pt.y -= (lab.frame.size.height - bottom) / 2;
    // Scan through each line to find the line containing the touch point y position
    for(CFIndex i = 0; i < linesCount; ++i) {
        line = (__bridge CTLineRef)[lines objectAtIndex:i];
        lineOrigin = lineOrigins[I];
        CGFloat descent, ascent;
        CGFloat width = CTLineGetTypographicBounds(line, &ascent, &descent,nil);
        if(pt.y < (floor(lineOrigin.y) + floor(descent))) {
            // Cater for text alignment set in the label itself (not in the attributed string)
            if(lab.textAlignment == NSTextAlignmentCenter) {
                pt.x -= (lab.frame.size.width - width) / 2;
            } else if (lab.textAlignment == NSTextAlignmentRight) {
                pt.x -= (lab.frame.size.width - width);
            }
            // Offset the touch position by the actual typeset line origin. pt is now the correct touch position with the line bounds
            pt.x -= lineOrigin.x;
            pt.y -= lineOrigin.y;
            // Find the text index within this line for the touch position
            CFIndex i =CTLineGetStringIndexForPosition(line, pt);
            // Iterate through each of the glyph runs to find the run containing the character index
            NSArray* glyphRuns = (__bridge id)CTLineGetGlyphRuns(line);
            CFIndex runCount = [glyphRuns count];
            for (CFIndex run = 0; run < runCount; ++ run) {
                CTRunRef glyphRun = (__bridge CTRunRef)[glyphRuns objectAtIndex:run];
                CFRange range = CTRunGetStringRange(glyphRun);
                if(i >= range.location && i<= range.location+range.length) {
                    dictionary = (__bridge NSDictionary*)CTRunGetAttributes(glyphRun);
                    break;
                }
            }
            if(dictionary) {
                break;
            }
        }
    }
    free(lineOrigins);
    CFRelease(frameRef);
    CFRelease(framesetter);
    return dictionary;
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,837评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,551评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,417评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,448评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,524评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,554评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,569评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,316评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,766评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,077评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,240评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,912评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,560评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,176评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,425评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,114评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,114评论 2 352

推荐阅读更多精彩内容

  • 新的工作遇到了困难,还没有理清楚思路。加上时间太久没有好好看书,觉得内心空荡。 节奏,乱了。我找不到我自己了。 想...
    女公子的剑庐阅读 380评论 0 0
  • 夜蔓过黑 莺声划走了最后一份白 向未来是一番新的模样 看着这漫天的乌云遍布 我听见了这雨声 滴滴答答 萦绕了整个大...
    千時阅读 284评论 2 7
  • 【今夕何夕】目录 欢迎戳回来 【连载】今夕何夕(12)险象环生 “应该是你弟弟回来了。”袁铁看着小楠道,“你弟弟是...
    我就叫秋男阅读 494评论 0 0
  • 今天弄了导航条,还插入了易烊千玺的图片
    4e7a0fcb4de6阅读 142评论 0 1