点击问题跳转
在这里我使用了两种方式去实现,一种是使用CoreText,另外一种是使用UITextView(基于TextKit,iOS7之后才可以使用)
CoreText
声明一个局部变量
@interface ReplyTextView()
{
CTFrameRef frame;
}
绘制字符串,@XXX部分使用蓝色字体(在本例子中是self.to_user_name部分)
- (void)drawRect:(CGRect)rect {
// Drawing code
if (self.user_name && self.to_user_name && self.content) {
NSString *combineText = [NSString stringWithFormat:@"%@@%@ %@",self.user_name,self.to_user_name,self.content];
self.combineAttText = [[NSMutableAttributedString alloc] initWithString:combineText];
[self.combineAttText beginEditing];
CTFontRef font = CTFontCreateWithName(CFSTR("AlNilePUA"), 12, NULL);
[self.combineAttText addAttribute:(__bridge id)kCTFontAttributeName value:(__bridge id)font range:NSMakeRange(0, self.combineAttText.length)];
// set user_name Color
[self.combineAttText addAttribute:(__bridge id)kCTForegroundColorAttributeName value:RGBCOLOR(37, 40, 57) range:NSMakeRange(0, self.user_name.length)];
// set to_user_name Color
[self.combineAttText addAttribute:(__bridge id)kCTForegroundColorAttributeName value:RGBCOLOR(8, 120, 198) range:NSMakeRange(self.user_name.length, self.to_user_name.length + 3)];
// set content Color
[self.combineAttText addAttribute:(__bridge id)kCTForegroundColorAttributeName value:RGBCOLOR(130, 130, 130) range:NSMakeRange(self.combineAttText.length - self.content.length, self.content.length)];
[self.combineAttText endEditing];
// CTFramesetter是CTFrame的创建工厂,NSAttributedString需要通过CTFrame绘制到界面上,得到CTFramesetter后,创建path(绘制路径),然后得到CTFrame,最后通过CTFrameDraw方法绘制到界面上
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)self.combineAttText);
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL ,CGRectMake(0, -2, self.bounds.size.width, self.bounds.size.height));
if (frame != nil) {
CFRelease(frame);
}
frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), path, NULL);
//获取当前(View)上下文以便于之后的绘画,这个是一个离屏。
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetTextMatrix(context , CGAffineTransformIdentity);
//压栈,压入图形状态栈中.每个图形上下文维护一个图形状态栈,并不是所有的当前绘画环境的图形状态的元素都被保存。图形状态中不考虑当前路径,所以不保存
//保存现在得上下文图形状态。不管后续对context上绘制什么都不会影响真正得屏幕。
CGContextSaveGState(context);
//x,y轴方向移动
CGContextTranslateCTM(context , 0 ,self.bounds.size.height);
//缩放x,y轴方向缩放,-1.0为反向1.0倍,坐标系转换,沿x轴翻转180度
CGContextScaleCTM(context, 1.0 ,-1.0);
CTFrameDraw(frame,context);
CGPathRelease(path);
CFRelease(framesetter);
}
}
判断点击文字的位置
- (long)indexAtPoint:(CGPoint)point{
point = CGPointMake(point.x, CGRectGetMaxY(self.bounds) - point.y); // 这里Y坐标系是反的,所以需要减
NSArray *lines = (__bridge NSArray *)(CTFrameGetLines(frame));
CGPoint origins[lines.count];
CTFrameGetLineOrigins(frame, CFRangeMake(0, lines.count), origins);
for(int i = 0; i < lines.count; i++) {
if(point.y > origins[i].y) {
CTLineRef line = (__bridge CTLineRef)([lines objectAtIndex:i]);
return CTLineGetStringIndexForPosition(line, point);
}
}
return 0;
}
这里是点击的时候判断点击位置,如果点击@XXX则做相应操作
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
UITouch *user_touch = [touches anyObject];
CGPoint touch_point = [user_touch locationInView:self];
long index = [self indexAtPoint:touch_point];
if (index > self.user_name.length && index < self.user_name.length + self.to_user_name.length + 3) {
// touch @user
if ([self.delegate respondsToSelector:@selector(touchShowHomePageArea:)]) {
[self.delegate touchShowHomePageArea:YES];
}
}
else{
// reply somebody
if ([self.delegate respondsToSelector:@selector(touchShowHomePageArea:)]) {
[self.delegate touchShowHomePageArea:NO];
}
}
}
使用UITextView(TextKit)
这里使用UITextView则简单得多
这里创建一个基于UITextView的类
#pragma mark - DrawCode
- (void)drawRect:(CGRect)rect {
if (self.user_name && self.to_user_name && self.content) {
NSString *combineText = [NSString stringWithFormat:@"%@@%@:%@",self.user_name,self.to_user_name,self.content];
self.attributedText = [[NSMutableAttributedString alloc] initWithString:combineText];
// 设置常规属性
[self setUpNormalAttribute];
// 设置表情链接
[self setUpEmojiAndLink];
// 注:点击链接反馈直接在UITextViewDelegate里面
}
}
#pragma mark - 设置常规属性
- (void)setUpNormalAttribute{
// 注:不能直接使用attributedText,只能copy然后再赋值
NSMutableAttributedString *mutStr = [self.attributedText mutableCopy];
// 设置评论人名字属性
[mutStr addAttributes:@{NSForegroundColorAttributeName :RGBCOLOR(37, 40, 57),
NSFontAttributeName :[UIFont systemFontOfSize:12.0]} range:NSMakeRange(0,[self.user_name length])];
// 设置内容
[mutStr addAttributes:@{NSForegroundColorAttributeName :RGBCOLOR(130, 130, 130),
NSFontAttributeName :[UIFont systemFontOfSize:12.0]} range:NSMakeRange(mutStr.length - [self.content length],[self.content length])];
self.attributedText = [mutStr copy];
}
#pragma mark - 设置表情链接
- (void)setUpEmojiAndLink{
NSMutableAttributedString * mutStr = [self.attributedText mutableCopy];
// 添加链接(点击链接反馈直接在UITextViewDelegate里面)
NSURL *url = [NSURL URLWithString:self.to_user_id];
[mutStr addAttribute:NSLinkAttributeName value:url range:NSMakeRange([self.user_name length],[self.to_user_name length] + 1)];
self.attributedText = [mutStr copy];
}
图文混排
这里图文混排给予UITextView
设置图片以及插入位置
- (void)setUpEmojiAndLink{
NSMutableAttributedString *mutStr = [self.textView.attributedText mutableCopy];
// Add Emoji
UIImage *image1 = [UIImage imageNamed:@"emoji"];
NSTextAttachment *attachment1 = [[NSTextAttachment alloc] init];
attachment1.bounds = CGRectMake(0, 0, 30, 30);
attachment1.image = image1;
NSAttributedString *attStr1 = [NSAttributedString attributedStringWithAttachment:attachment1];
[mutStr insertAttributedString:attStr1 atIndex:30];
// Add Emoji2
UIImage *image2 = [UIImage imageNamed:@"label1"];
NSTextAttachment *attachment2 = [[NSTextAttachment alloc] init];
attachment2.bounds = CGRectMake(0, 0, 50, 10);
attachment2.image = image2;
NSAttributedString *attStr2 = [NSAttributedString attributedStringWithAttachment:attachment2];
[mutStr insertAttributedString:attStr2 atIndex:40];
[self.textView setAttributedText:[mutStr mutableCopy]];
}
设置环绕路径
- (void)setLoopPath{
// Set Location Of ImageView
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(120, 20, 100, 50)];
imageView.image = [UIImage imageNamed:@"label2"];
[self.view addSubview:imageView];
// Set Loop Path
UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(100, 15, 100, 50)];
self.textView.textContainer.exclusionPaths = @[path];
}
效果图