我已将动态文本绘制到自定义UIImageView中。文本可以包含:-)或;-)之类的字符组合,我想用PNG图像替换。
对于下面的一堆代码,我深表歉意。
创建CTRunDelegate的代码如下:
CTRunDelegateCallbacks callbacks;
callbacks.version = kCTRunDelegateVersion1;
callbacks.dealloc = emoticonDeallocationCallback;
callbacks.getAscent = emoticonGetAscentCallback;
callbacks.getDescent = emoticonGetDescentCallback;
callbacks.getWidth = emoticonGetWidthCallback;
// Functions: emoticonDeallocationCallback, emoticonGetAscentCallback, emoticonGetDescentCallback, emoticonGetWidthCallback are properly defined callback functions
CTRunDelegateRef ctrun_delegate = CTRunDelegateCreate(&callbacks, self);
// self is what delegate will be using as void*refCon parameter
用于创建属性字符串的代码是:
NSMutableAttributedString* attString = [[NSMutableAttributedString alloc] initWithString:self.data attributes:attrs];
// self.data is string containing text
// attrs is just setting for font type and color
然后,我将CTRunDelegate添加到此字符串:
CFAttributedStringSetAttribute((CFMutableAttributedStringRef)attString, range, kCTRunDelegateAttributeName, ctrun_delegate);
// where range is for one single emoticon location in text (eg. location=5, length = 2)
// ctrun_delegate is previously created delegate for certain type of emoticon
回调函数的定义如下:
void emoticonDeallocationCallback(void*refCon)
{
// dealloc code goes here
}
CGFloat emoticonGetAscentCallback(void * refCon)
{
return 10.0;
}
CGFloat emoticonGetDescentCallback(void * refCon)
{
return 4.0;
}
CGFloat emoticonGetWidthCallback(void * refCon)
{
return 30.0;
}
现在所有这些工作正常-我调用了回调函数,并且可以看到宽度,上升和下降影响检测到的“表情符号字符组合”之前和之后文本的绘制方式。
现在,我想在产生“孔”的位置绘制图像,但是我找不到任何文档可以指导我如何在每个回调中获取像素(或其他坐标)坐标。
谁能指导我阅读这些内容?
提前致谢!
聚苯乙烯
据我所知,在调用CTFramesetterCreateWithAttributedString时会调用回调。因此,基本上没有图纸在进行中。我找不到任何显示表情符号位置与绘制文本中的位置匹配的示例。能做到吗
我找到了解决方案!
回顾一下:问题是使用CoreText将文本绘制到UIImageView中,除了明显的字体类型和颜色格式外,此文本还需要用小图像替换文本的一部分,并在替换子文本所在的位置插入(例如:- )将变成笑脸)。
这是如何做:
1)在提供的字符串中搜索所有受支持的表情符号(例如,搜索:-)子字符串)
NSRange found = [self.rawtext rangeOfString:emoticonString options:NSCaseInsensitiveSearch range:searchRange];
如果发现出现的情况,请将其存储在CFRange中:
CFRange cf_found = CFRangeMake(found.location, found.length);
如果要搜索多个不同的图释(例如::) :-) ;-);)等),请按其位置的升序对所有找到的出现进行排序。
2)替换所有要用图像替换的图释子字符串(例如:-)。此后,您还必须更新找到的位置以匹配这些新空间。它并不像听起来那么复杂。
3)对每个表情使用CTRunDelegateCreate将回调添加到新创建的字符串(不带:-的字符串,而是[SPACE])。
4)回调函数显然应该根据您将使用的图像大小返回正确的图释宽度。
5)一旦您将执行CTFramesetterCreateWithAttributedString,这些回调函数也将被执行,从而提供框架设定器数据,这些数据稍后将用于创建用于在给定框架路径中绘制的字形。
6)现在是我想念的部分:一旦使用CTFramesetterCreateFrame为照排机创建框架,请遍历所有找到的图释并执行以下操作:
从帧中获取行数,并获取第一行的原点:
CFArrayRef lines = CTFrameGetLines(frame);
int linenum = CFArrayGetCount(lines);
CGPoint origins[linenum];
CTFrameGetLineOrigins(frame, CFRangeMake(0, linenum), origins);
在每个表情符号的所有行中循环,寻找包含该表情符号的字形(基于每个表情符号的range.location和每个字形中的字符数):
(灵感来自这里:CTRunGetImageBounds返回不正确的结果)
int eloc = emoticon.range.location; // emoticon's location in text
for( int i = 0; i<linenum; i++ )
{
CTLineRef line = (CTLineRef)CFArrayGetValueAtIndex(lines, i);
CFArrayRef gruns = CTLineGetGlyphRuns(line);
int grunnum = CFArrayGetCount(gruns);
for( int j = 0; j<grunnum; j++ )
{
CTRunRef grun = (CTRunRef) CFArrayGetValueAtIndex(gruns, j);
int glyphnum = CTRunGetGlyphCount(grun);
if( eloc > glyphnum )
{
eloc -= glyphnum;
}
else
{
CFRange runRange = CTRunGetStringRange(grun);
CGRect runBounds;
CGFloat ascent,descent;
runBounds.size.width = CTRunGetTypographicBounds(grun, CFRangeMake(0, 0), &ascent, &descent, NULL);
runBounds.size.height = ascent + descent;
CGFloat xOffset = CTLineGetOffsetForStringIndex(line, runRange.location, NULL);
runBounds.origin.x = origins[i].x + xOffset;
runBounds.origin.y = origins[i].y;
runBounds.origin.y -= descent;
emoticon.location = CGPointMake(runBounds.origin.x + runBounds.size.width, runBounds.origin.y);
emoticon.size = CGPointMake([emoticon EmoticonWidth] ,runBounds.size.height);
break;
}
}
}
请不要将此代码当作复制粘贴和将要使用的代码,因为我不得不剥离许多其他内容-因此,这只是为了说明我所做的事情,而不是让您按原样使用它。
7)最后,我可以创建上下文并在正确的位置绘制文本和表情符号:
if(currentContext)
{
CGContextSaveGState(currentContext);
{
CGContextSetTextMatrix(currentContext, CGAffineTransformIdentity);
CTFrameDraw(frame, currentContext);
}
CGContextRestoreGState(currentContext);
if( foundEmoticons != nil )
{
for( FoundEmoticon *emoticon in foundEmoticons )
{
[emoticon DrawInContext:currentContext];
}
}
}
和绘制图释的功能(我只是绘制它的边界和枢轴点):
-(void) DrawInContext:(CGContext*)currentContext
{
CGFloat R = round(10.0 * [self randomFloat] ) * 0.1;
CGFloat G = round(10.0 * [self randomFloat] ) * 0.1;
CGFloat B = round(10.0 * [self randomFloat] ) * 0.1;
CGContextSetRGBStrokeColor(currentContext,R,G,B,1.0);
CGFloat pivotSize = 8.0;
CGContextBeginPath(currentContext);
CGContextMoveToPoint(currentContext, self.location.x, self.location.y - pivotSize);
CGContextAddLineToPoint(currentContext, self.location.x, self.location.y + pivotSize);
CGContextMoveToPoint(currentContext, self.location.x - pivotSize, self.location.y);
CGContextAddLineToPoint(currentContext, self.location.x + pivotSize, self.location.y);
CGContextDrawPath(currentContext, kCGPathStroke);
CGContextBeginPath(currentContext);
CGContextMoveToPoint(currentContext, self.location.x, self.location.y);
CGContextAddLineToPoint(currentContext, self.location.x + self.size.x, self.location.y);
CGContextAddLineToPoint(currentContext, self.location.x + self.size.x, self.location.y + self.size.y);
CGContextAddLineToPoint(currentContext, self.location.x, self.location.y + self.size.y);
CGContextAddLineToPoint(currentContext, self.location.x, self.location.y);
CGContextDrawPath(currentContext, kCGPathStroke);
}
结果图像:http : //i57.tinypic.com/rigis5.png
:-)))
聚苯乙烯
这是带有多行的结果图像:http : //i61.tinypic.com/2pyce83.png
聚苯硫醚
这是具有多行和带有表情符号的PNG图像的结果图像:http : //i61.tinypic.com/23ixr1y.png
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句