html中超链接z-index,超链接Label - AAAAdler的个人空间 - OSCHINA - 中文开源技术交流社区...

#import 

typedef void(^LinkTap)(NSRange range, NSURL* url);

@interface LinkLabel : UIView

@property (nonatomic, copy) NSString* text;

@property (nonatomic, strong) UIColor* textColor;

@property (nonatomic, assign) CGFloat fontSize;

@property (nonatomic, copy) LinkTap tapLink;

- (void)addLinkRange:(NSRange)range withUrl:(NSURL *)url;

@end

#import "LinkLabel.h"

#import 

@interface LinkLabel () {

CTFrameRef _textFrame;

NSMutableArray* _lineRects;

NSMutableDictionary* _linkDic;// 存储链接文本及其range位置

}

@end

@implementation LinkLabel

- (instancetype)init {

self = [super init];

if (self) {

[self commontInit];

}

return self;

}

- (instancetype)initWithCoder:(NSCoder *)aDecoder {

self = [super initWithCoder:aDecoder];

if (self) {

[self commontInit];

}

return self;

}

- (instancetype)initWithFrame:(CGRect)frame {

self = [super initWithFrame:frame];

if (self) {

[self commontInit];

}

return self;

}

- (void)commontInit {

UIGestureRecognizer * tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(userTapGesture:)];

[self addGestureRecognizer:tapRecognizer];

self.userInteractionEnabled = YES;

_lineRects = [NSMutableArray array];

_linkDic = [NSMutableDictionary dictionary];

}

- (void)addLinkRange:(NSRange)range withUrl:(NSURL *)url {

[_linkDic setObject:url forKey:[NSValue valueWithRange:range]];

}

// 正则表达式匹配超链接文本

- (void)matchLinkString:(NSString *)string {

NSError *error;

NSString *regulaStr = @"((http[s]{0,1}|ftp)://[a-zA-Z0-9\\.\\-]+\\.([a-zA-Z]{2,4})(:\\d+)?(/[a-zA-Z0-9\\.\\-~!@#$%^&*+?:_/=<>]*)?)|(www.[a-zA-Z0-9\\.\\-]+\\.([a-zA-Z]{2,4})(:\\d+)?(/[a-zA-Z0-9\\.\\-~!@#$%^&*+?:_/=<>]*)?)";

NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:regulaStr

options:NSRegularExpressionCaseInsensitive

error:&error];

NSArray *arrayOfAllMatches = [regex matchesInString:string options:0 range:NSMakeRange(0, [string length])];

for (NSTextCheckingResult *match in arrayOfAllMatches)

{

NSString* linkStrForMatch = [string substringWithRange:match.range];

[_linkDic setObject:[NSURL URLWithString:linkStrForMatch] forKey:[NSValue valueWithRange:match.range]];

}

}

- (void)setText:(NSString *)text {

_text = text;

[self matchLinkString:text];

}

- (void)drawRect:(CGRect)rect {

[super drawRect:rect];

NSMutableAttributedString *attString = [[NSMutableAttributedString alloc] initWithString:_text];

UIFont* font = [UIFont systemFontOfSize:_fontSize];

[attString addAttribute:(id)kCTFontAttributeName value:font range:NSMakeRange(0, attString.length)];

if (_linkDic.count) {

[_linkDic enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {

NSRange range = [key rangeValue];

[attString addAttribute:(id)kCTForegroundColorAttributeName value:(id)[UIColor blueColor].CGColor range:range];

}];

}

CGContextRef context = UIGraphicsGetCurrentContext();

// 翻转坐标系

CGContextSetTextMatrix(context, CGAffineTransformIdentity);

CGContextTranslateCTM(context, 0, self.bounds.size.height);

CGContextScaleCTM(context, 1.0, -1.0);

CGMutablePathRef path = CGPathCreateMutable();

CGPathAddRect(path, NULL, self.bounds);

CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attString);

CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, [attString length]), path, NULL);

CTFrameDraw(frame, context);

//    CFRelease(frame);

CFArrayRef lines = CTFrameGetLines(frame);

CFIndex count = CFArrayGetCount(lines);

// 获得每一行的 origin 坐标

CGPoint origins[count];

CTFrameGetLineOrigins(frame, CFRangeMake(0,0), origins);

// 翻转坐标系

CGAffineTransform transform =  CGAffineTransformMakeTranslation(0, self.bounds.size.height);

transform = CGAffineTransformScale(transform, 1.f, -1.f);

for (int i = 0; i 

CGPoint linePoint = origins[i];

CTLineRef line = CFArrayGetValueAtIndex(lines, i);

// 获得每一行的 CGRect 信息

CGRect flippedRect = [self getLineBounds:line point:linePoint];

CGRect rect = CGRectApplyAffineTransform(flippedRect, transform);

[_lineRects addObject:[NSValue valueWithCGRect:rect]];

}

_textFrame = frame;

CFRelease(path);

CFRelease(framesetter);

}

- (CGRect)getLineBounds:(CTLineRef)line point:(CGPoint)point {

CGFloat ascent = 0.0f;

CGFloat descent = 0.0f;

CGFloat leading = 0.0f;

//ascent是文本上线,descent是文本下线,leading是文本起始线

CGFloat width = (CGFloat)CTLineGetTypographicBounds(line, &ascent, &descent, &leading);

CGFloat height = ascent + descent;

return CGRectMake(point.x, point.y - descent, width, height);

}

- (void)userTapGesture:(UIGestureRecognizer *)recognizer {

CGPoint point = [recognizer locationInView:self];

CFArrayRef lines = CTFrameGetLines(_textFrame);

CFIndex count = CFArrayGetCount(lines);

for (int i = 0; i 

CTLineRef line = CFArrayGetValueAtIndex(lines, i);

CGRect rect = [_lineRects[i] CGRectValue];

if (CGRectContainsPoint(rect, point)) {

// 将点击的坐标转换成相对于当前行的坐标

CGPoint relativePoint = CGPointMake(point.x - CGRectGetMinX(rect), point.y - CGRectGetMinY(rect));

// 获得当前点击坐标对应的字符串偏移

// 点击坐标最近的光标的最近字符的index,点击字符前半部分会定位到上一个字符的index,点击后半部分才得到正确的index

CFIndex idx = CTLineGetStringIndexForPosition(line, relativePoint);

CGFloat glyphStart;

// 根据index获取对应字符据行初始位置距离

CTLineGetOffsetForStringIndex(line, idx, &glyphStart);

if (relativePoint.x 

--idx;

}

[self matchAndOpenLinkUrl:idx];

break;

}

}

}

- (void)matchAndOpenLinkUrl:(CFIndex)index {

[_linkDic enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {

NSRange range = [key rangeValue];

if (NSLocationInRange(index, range)) {

NSURL* url = (NSURL *)obj;

if (self.tapLink) {

self.tapLink(range, url);

}

*stop = YES;

}

}];

}

@end

xib上使用例子:

@property (weak, nonatomic) IBOutlet LinkLabel *linkLabel;

_linkLabel.text = @"陷阵@86之志有死无生http://ddd.edu,一点寒芒先到,随后枪出如龙。纵使敌众我寡,末将亦能万军从中取敌将首级www.baidu.com";

_linkLabel.fontSize = 17;

[_linkLabel addLinkRange:NSMakeRange(2, 3) withUrl:[NSURL URLWithString:@"www.google.com"]];

_linkLabel.tapLink = ^(NSRange range, NSURL* url) {

NSLog(@"url:%@", url.absoluteString);

};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值