iOS CoreText 实现帖子点赞文本(事件响应)

目前社交类型的App也是层出不穷,无论是QQ的说说,还是微信的动态,微博的帖子。这种类型的App都会涉及到点赞文本的显示。

以下将介绍如何实现类型的文本点击事件响应:

1.创建一个项目,创建一个类名为MyLabel,继承UILabel.

2.在MyLabel.h中实现以下代码:

//

//  MyLabel.h

//  CoreText_6_12

//

//  Created by he xiulian on 16/6/12.

//  Copyright ? 2016年 hexiulian. All rights reserved.

//

#import

/**

*  选中哪个人回调信息

*

*  @param arrIndex 昵称在的数组下标

*  @param msg      昵称

*/

typedefvoid(^CallBackZan)(intarrIndex,NSString*msg);

@interfaceMyLabel:UILabel

{

//富文本样式

NSMutableAttributedString*content;

}

@property(nonatomic,strong)NSMutableArray*mArrData;//点赞的信息数组

//回调属性(赋值时实现代码块点击某个昵称时间响应功能)

@property(nonatomic,strong)CallBackZanzanHandelBlock;

@end

3.在MyLabel.m中实现标签的初始化方法,设置文本样式方法,实现点击方法

3.1 在MyLabel.m中包含  #import

3.2 添加延展

//延展

@interfaceMyLabel()

{

CTFrameRef_frame;//ct的frame,coreText绘制要用

}

@end

3.3 实现初始化方法:

-(instancetype)initWithFrame:(CGRect)frame

{

if(self=[superinitWithFrame:frame])

{

self.mArrData=[NSMutableArraynew];

self.numberOfLines=0;//自动换行

}

returnself;

}

3.4 重写数组的set方法给文本赋值,并设置样式:

//重写数组的set方法

-(void)setMArrData:(NSMutableArray*)mArrData

{

//给数组赋值,注意不要写self.mArrData

_mArrData=mArrData;

NSMutableString*strResult=[NSMutableStringstringWithString:@""];

//拼接文本

for(inti=0;i

{

[strResult appendString:@"@"];//拼接名字前的@

[strResult appendString:mArrData[i]];//拼接名字

if(i!=mArrData.count-1)//除了最后一个都加分割符

{

[strResult appendString:@"、"];

}

}

[strResult appendString:@"觉得很赞"];

//给文本赋值

self.text=strResult;

[selfbuildAttribute];

}

//创建NSMutableAttributedString,解析所有触发点击事件

-(void)buildAttribute

{

//获取标签上的所有内容转为可修饰的富文本类型

content=[[NSMutableAttributedStringalloc]initWithString:self.text];

//这里对需要进行点击事件的字符heightlight效果

//点赞人的所有名字都是绿色的

[content  setAttributes:@{NSForegroundColorAttributeName:

[UIColorcolorWithRed:0.165green:0.604blue:0.212alpha:1.000]}

range:NSMakeRange(0,self.text.length-4)];

//倒数4个字符是灰色的

[content  setAttributes:@{NSForegroundColorAttributeName:

[UIColorcolorWithWhite:0.663alpha:1.000]}

range:NSMakeRange(self.text.length-4,4)];

//赋上新样式的内容

self.attributedText=content;

}

3.5 关于CoreText的一些知识补充:

iOS CoreText 实现帖子点赞文本(事件响应)_第1张图片

1.boundingbox(边界框bbox),这是一个假想的框子,它尽可能紧密的装入字形。

2.baseline(基线),一条假想的线,一行上的字形都以此线作为上下位置的参考,在这条线的左侧存在一个点叫做

基线的原点,

3.ascent(上行高度)从原点到字体中最高(这里的高深都是以基线为参照线的)的字形的顶部的距离,ascent是

一个正值

4.descent(下行高度)从原点到字体中最深的字形底部的距离,descent是一个负值(比如一个字体原点到最深的

字形的底部的距离为2,那么descent就为-2)

5.linegap(行距),linegap也可以称作leading(其实准确点讲应该叫做Externalleading),行高

lineHeight则可以通过ascent+|descent|+linegap来计算。

Core Text绘制的流程:

iOS CoreText 实现帖子点赞文本(事件响应)_第2张图片

CTFrame作为一个整体的画布(Canvas),其中由行(CTLine)组成,而每行可以分为一个或多个小方块(CTRun).

1.framesetterframesetter对应的类型是CTFramesetter,通过CFAttributedString进行初始化,

它作为CTFrame对象的生产工厂,负责根据path生产对应的CTFrame

2.CTFrameCTFrame是可以通过CTFrameDraw函数直接绘制到context上的,可以在绘制之前,

操作CTFrame中的CTLine,进行一些参数的微调

3。CTLine可以看做CoreText绘制中的一行的对象通过它可以获得当前行的line ascent,line descent

,line leading,还可以获得Line下的所有GlyphRuns

4。CTRun或者叫做GlyphRun,是一组共享想相同attributes(属性)的字形的集合体

可参考:http://my.oschina.net/megan/blog/269042

可参考:http://blog.csdn.net/fengsh998/article/details/8691823/

3.6  core Text的绘制及实现响应:

-(void)drawRect:(CGRect)rect

{

//获取上下文

CGContextRefcontext=UIGraphicsGetCurrentContext();

//设置context的ctm,用于适应core text的坐标体系

//保存现在得上下文图形状态。不管后续对context上绘制什么都不会影响真正得屏幕。

CGContextSaveGState(context);

//设置文本矩阵(为基矩阵)

CGContextSetTextMatrix(context,CGAffineTransformIdentity);

//x,y轴方向移动

CGContextTranslateCTM(context,0,rect.size.height);

/*

Core Text一开始便是定位于桌面的排版系统,使用了传统的原点在左下角的坐标系,所以它在绘制文本的时候都是参照左下角的原点进行绘制的。 但是iOS的UIView的drawRect方法的context被做了次flip,如果你啥也不做处理,直接在这个context上进行Core Text绘制,你会发现文字是镜像且上下颠倒。

*/

//Core Graphics的context使用的坐标系的原点是在左下角

//View为了其实现的便捷将原点变换到左上角

//所以在UIView的drawRect方法中的context上进行Core Text绘制之前需要对context进行一次Flip。

////缩放x,y轴方向缩放,-1.0为反向1.0倍,坐标系转换,沿x轴翻转180度

CGContextScaleCTM(context,1.0,-1.0);

//设置CTFramesetter(获取富文本的frame大小)

CTFramesetterRefframesetter=CTFramesetterCreateWithAttributedString((CFAttributedStringRef)content);

//创建可变的路径

CGMutablePathRefpath=CGPathCreateMutable();

//添加路径并设置frame

CGPathAddRect(path,NULL,CGRectMake(0,0,rect.size.width,rect.size.height));

//创建CTFrame

_frame=CTFramesetterCreateFrame(framesetter,CFRangeMake(0,content.length),path,NULL);

//把文字内容绘制出来

CTFrameDraw(_frame,context);

//获取画出来的内容的行数

CFArrayReflines=CTFrameGetLines(_frame);

//获取每行的原点坐标

CGPointlineOrigins[CFArrayGetCount(lines)];

//获取行基线起点

CTFrameGetLineOrigins(_frame,CFRangeMake(0,0),lineOrigins);

//遍历文本的行数

for(inti=0;i

{

CTLineRefline=CFArrayGetValueAtIndex(lines,i);

CGFloatlineAscent;//上行线

CGFloatlineDescent;//下行线

CGFloatlineLeading;//返回的主要线路

//获取每行的宽度和高度

CTLineGetTypographicBounds(line,&lineAscent,&lineDescent,&lineLeading);

//获取每个CTRun

CFArrayRefruns=CTLineGetGlyphRuns(line);

//遍历每一行的每一个字符

for(intj=0;j

{

CGFloatrunAscent;

CGFloatrunDescent;

CGPointlineOrigin=lineOrigins[i];

//获取每个CTRun

CTRunRefrun=CFArrayGetValueAtIndex(runs,j);

CGRectrunRect;

//调整CTRun的rect

runRect.size.width=CTRunGetTypographicBounds(run,CFRangeMake(0,0),&runAscent,&runDescent,NULL);

runRect=CGRectMake(lineOrigin.x+CTLineGetOffsetForStringIndex(line,CTRunGetStringRange(run).location,NULL),lineOrigin.y-runDescent,runRect.size.width,runAscent+runDescent);

}

}

//绘制

CGContextRestoreGState(context);

}

//接受触摸事件

-(void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event

{

//获取UITouch对象

UITouch*touch=[touches anyObject];

//获取触摸点击当前view的坐标位置

CGPointlocation=[touch locationInView:self];

//获取每一行

CFArrayReflines=CTFrameGetLines(_frame);

CGPointorigins[CFArrayGetCount(lines)];

//获取每行的原点坐标

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

CTLineRefline=NULL;

CGPointlineOrigin=CGPointZero;

for(inti=0;i

{

CGPointorigin=origins[i];

CGPathRefpath=CTFrameGetPath(_frame);

//获取整个CTFrame的大小

CGRectrect=CGPathGetBoundingBox(path);

//坐标转换,把每行的原点坐标转换为uiview的坐标体系(上下对称)

CGFloaty=rect.origin.y+rect.size.height-origin.y;

//判断点击的位置处于哪一行范围内

if((location.y<=y)&&(location.x>=origin.x))

{

line=CFArrayGetValueAtIndex(lines,i);

lineOrigin=origin;

break;

}

}

location.x-=lineOrigin.x;

//获取点击位置所处的字符位置,就是相当于点击了第几个字符

CFIndexindex=CTLineGetStringIndexForPosition(line,location);

//点最后四个字没反应

if(index>=self.text.length-4)

{

return;

}

//判断点击的字符是否在需要处理点击事件的字符串范围内,这里是hard code了需要触发事件的字符串范围

if(index>=1&&index<=self.text.length-4)

{

//存放选到的名字

NSString*strSelect=@"";

//记录选中哪个下标

longtextIndex=0;

for(inti=0;i

{

//逐个排除

strSelect=self.mArrData[i];

//下标累加

textIndex+=strSelect.length;

//是选中的那个字符串

if(index<=textIndex)

{

self.zanHandelBlock(i,strSelect);

//找到

break;

}

textIndex++;//补充一个(@)的长度

textIndex++;//补充一个(、)的长度

}

}

}

4. 在ViewController.m中包含MyLabel.h创建标签:

#import "MyLabel.h"

-(void)viewDidLoad{

[superviewDidLoad];

//创建标签

MyLabel*lblSupport=[[MyLabelalloc]initWithFrame:CGRectMake(20,60,self.view.frame.size.width-40,120)];

//创建模拟数据

NSMutableArray*mArr=[NSMutableArrayarrayWithArray:@[@"似梦非梦",@"庄周梦蝶",@"微光",@"依然怀旧",@"YouniTsa",@"一念执着",@"不说话",@"BuLaiEng"]];

//给数组赋值,并给文本赋值

lblSupport.mArrData=mArr;

//打开用户交互,响应点击事件

lblSupport.userInteractionEnabled=YES;

//显示

[self.view addSubview:lblSupport];

//给点击某个昵称响应事件的代码块赋值

lblSupport.zanHandelBlock=^(intarrIndex,NSString*nickName)

{

//控制器

UIAlertController*alertVC=[UIAlertControlleralertControllerWithTitle:@"提示"message:nickName preferredStyle:UIAlertControllerStyleAlert];

//确认

UIAlertAction*ok=[UIAlertActionactionWithTitle:@"ok"style:UIAlertActionStyleDefaulthandler:^(UIAlertAction*_Nonnullaction){

}];

//取消

UIAlertAction*cancle=[UIAlertActionactionWithTitle:@"cancle"style:UIAlertActionStyleCancelhandler:^(UIAlertAction*_Nonnullaction){

}];

//添加响应按钮

[alertVC addAction:ok];

[alertVC addAction:cancle];

//弹框

[selfpresentViewController:alertVC animated:YES completion:nil];

};

}

效果图如下:

iOS CoreText 实现帖子点赞文本(事件响应)_第3张图片

iOS CoreText 实现帖子点赞文本(事件响应)_第4张图片

你可能感兴趣的:(iOS CoreText 实现帖子点赞文本(事件响应))