需要导入CoreText框架
效果图:
-
日历控件点击2019:
-
点击2019打印的日志:
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;
}