当前位置:   article > 正文

CoreText高级应用——富文本、按钮、输入框的混编_ios好用的富文本编辑器支持@#

ios好用的富文本编辑器支持@#

关于CoreText基础,推崇紫色大番薯的《CoreText原理及基本使用方法》一文,有珠玉在前,我就不再详述。

CoreText是用于处理文字和字体的底层技术,多用于富文本排版布局。IOS6.0以后UILabel、UITextField增加了新的富文本处理方式使用起来要比CoreText友好的多。现在网上很多CoreText应用实例,都可以使用UILabel、UITextField更加简便的给予实现。但是总有一些复杂的问题必须用到CoreText,这里分享一个我遇到过实例。


解决的问题:

在view中自动排版展示文档格式储存的试卷,文档的首行为标题,填空题需要直接在题目中填写答案, 选择题的选项以按钮的形式展现。

原始文件实例

ETHNOGRAPHY IN BUSINESS
1. It can be used in business:
• to investigate customer needs and ……………………
• to help …………………… develop new designs
2. What change in the road network is known to have benefited the town most?
○ the construction of a bypass
○ the development of cycle paths
○ the banning of cars from certain streets

最终显示效果


解决问题的思路:

1. 把文档转换为富文本

2. 使用CoreText绘制富文本

3. 确定输入框,选项位置

4. 创建UITextField作为输入框,创建UIButton作为选项,

1. 文档转换为富文本

以下信息要加入到富文本之中:

  • 行间距、段间距等格式信息
  • 标题样式
  • 输入框和按钮的标记

  1. -(NSMutableAttributedString *)getMutableAttributedString{
  2. NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:_text];
  3. NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
  4. [paragraphStyle setLineSpacing:5];
  5. [paragraphStyle setParagraphSpacingBefore:8];
  6. [attributedString addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, [_text length])];
  7. //第一行为标题
  8. NSRange firstLineRange=[_text lineRangeForRange:NSMakeRange(0, 1)];
  9. [attributedString addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:20] range:firstLineRange]; // 6.0+
  10. //………………处添加UITextView作为输入框
  11. NSRange inputRange=[_text rangeOfString:@"………………"];
  12. while(inputRange.length>0){
  13. [attributedString addAttribute:(id)@"FTCoreTextDataName" value:(id)@"input" range:inputRange];
  14. if (inputRange.length+inputRange.location==_text.length) {
  15. inputRange=NSMakeRange(0,0);
  16. } else {
  17. inputRange=[_text rangeOfString:@"………………" options:0 range:NSMakeRange(inputRange.location+1,_text.length-inputRange.length-inputRange.location-1)];
  18. }
  19. }
  20. //○开始行为按钮,
  21. NSRange buttonRange=[_text rangeOfString:@"○"];
  22. while(buttonRange.length>0){
  23. [attributedString addAttribute:(id)@"FTCoreTextDataName" value:(id)@"button" range:buttonRange];
  24. buttonRange=[_text rangeOfString:@"○" options:0 range:NSMakeRange(buttonRange.location+1,_text.length-buttonRange.length-buttonRange.location-1)];
  25. }
  26. return attributedString;
  27. }

2. 使用CoreText绘制富文本

  1. 填充背景色
  2. 翻转坐标系
  3. 创建绘制区域
  4. 绘制文本

  1. //获取当前上下文
  2. CGContextRef context = UIGraphicsGetCurrentContext();
  3. //填充背景色
  4. [self.backgroundColor setFill];
  5. CGContextFillRect(context, rect);
  6. //翻转坐标系步骤
  7. //设置当前文本矩阵
  8. CGContextSetTextMatrix(context, CGAffineTransformIdentity);
  9. //文本沿y轴移动
  10. CGContextTranslateCTM(context, 0, self.bounds.size.height);
  11. //文本翻转成为CoreText坐标系
  12. CGContextScaleCTM(context, 1.0, -1.0);
  13. //获取NSMutableAttributedString
  14. NSMutableAttributedString *attributedString=[self getMutableAttributedString];
  15. //根据AttString生成CTFramesetterRef
  16. CTFramesetterRef ctFramesetter = CTFramesetterCreateWithAttributedString((CFMutableAttributedStringRef)attributedString);
  17. //创建绘制区域
  18. CGMutablePathRef path = CGPathCreateMutable();
  19. CGRect bounds = CGRectMake(0.0, 0.0, self.bounds.size.width, self.bounds.size.height);
  20. CGPathAddRect(path, NULL, bounds);
  21. //绘制文本
  22. CTFrameRef ctFrame = CTFramesetterCreateFrame(ctFramesetter,CFRangeMake(0, 0), path, NULL);
  23. CTFrameDraw(ctFrame, context);

3.确定输入框,选项位置

遍历每一个CTRunRef,查找我们在富文本中加入的标记

  1. for (int i = 0; i < CFArrayGetCount(lines); i++) {
  2. CTLineRef line = CFArrayGetValueAtIndex(lines, i);
  3. CGFloat lineAscent;
  4. CGFloat lineDescent;
  5. CGFloat lineLeading;
  6. CTLineGetTypographicBounds(line, &lineAscent, &lineDescent, &lineLeading);
  7. CFArrayRef runs = CTLineGetGlyphRuns(line);
  8. //遍历每一个CTRunRef
  9. for (int j = 0; j < CFArrayGetCount(runs); j++) {
  10. CGPoint lineOrigin = lineOrigins[i];
  11. CTRunRef run = CFArrayGetValueAtIndex(runs, j);
  12. NSDictionary* attributes = (NSDictionary*)CTRunGetAttributes(run);
  13. const CGPoint *point=CTRunGetPositionsPtr(run);
  14. NSString *attributeName = [attributes objectForKey:@"FTCoreTextDataName"];
  15. if ([attributeName isEqualToString:@"input"]) {
  16. //输入框标记
  17. 。。。。。。
  18. }else if ([attributeName isEqualToString:@"button"]){
  19. //按钮标记
  20. 。。。。。。 }
  21. }
  22. }

4.创建输入框及选项按钮

此处需注意CoreText坐标系UIKit坐标系的换算,新建控件使用的是UIKit坐标系

创建输入框

  1. UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(point[0].x+7, self.frame.size.height-lineOrigin.y-14, 150.0f, 20.0f)];
  2. [textField setBorderStyle:UITextBorderStyleNone]; //外框类型
  3. textField.placeholder = @""; //默认显示的字
  4. textField.font=[UIFont fontWithName:@"TimesNewRomanPSMT" size:12.f];
  5. textField.textColor=[UIColor blueColor];
  6. [self addSubview:textField];

创建按钮

  1. UIButton *button =[[UIButton alloc]initWithFrame:CGRectMake(point[0].x-5, self.frame.size.height-lineOrigin.y-16, 250, 22.0f)];
  2. UIColor *ucolor=[UIColor lightGrayColor];
  3. [button.layer setMasksToBounds:YES];
  4. [button.layer setCornerRadius:7.0]; //设置矩圆角半径
  5. [button.layer setBorderWidth:1.0]; //边框宽度
  6. [button.layer setBorderColor:ucolor.CGColor];//边框颜色
  7. [self addSubview:button];
  8. // 为UIButton关联响应事件
  9. [self.delegate addCoreTextViewObject:button type:@"button"];

5.其他注意事项

  1. 输入框和按钮只需要在页面第一次加载的时候创建,要避免重复创建
  2. 新建的输入框和按钮需要传递给ViewController,由ViewController来响应事件。

完整drawRect()代码

  1. - (void)drawRect:(CGRect)rect {
  2. //获取当前上下文
  3. CGContextRef context = UIGraphicsGetCurrentContext();
  4. //填充背景色
  5. [self.backgroundColor setFill];
  6. CGContextFillRect(context, rect);
  7. //翻转坐标系步骤
  8. //设置当前文本矩阵
  9. CGContextSetTextMatrix(context, CGAffineTransformIdentity);
  10. //文本沿y轴移动
  11. CGContextTranslateCTM(context, 0, self.bounds.size.height);
  12. //文本翻转成为CoreText坐标系
  13. CGContextScaleCTM(context, 1.0, -1.0);
  14. //获取NSMutableAttributedString
  15. NSMutableAttributedString *attributedString=[self getMutableAttributedString];
  16. //根据AttString生成CTFramesetterRef
  17. CTFramesetterRef ctFramesetter = CTFramesetterCreateWithAttributedString((CFMutableAttributedStringRef)attributedString);
  18. //创建绘制区域
  19. CGMutablePathRef path = CGPathCreateMutable();
  20. CGRect bounds = CGRectMake(0.0, 0.0, self.bounds.size.width, self.bounds.size.height);
  21. CGPathAddRect(path, NULL, bounds);
  22. //绘制文本
  23. CTFrameRef ctFrame = CTFramesetterCreateFrame(ctFramesetter,CFRangeMake(0, 0), path, NULL);
  24. CTFrameDraw(ctFrame, context);
  25. //获取CTLine数组
  26. CFArrayRef lines = CTFrameGetLines(ctFrame);
  27. CGPoint lineOrigins[CFArrayGetCount(lines)];
  28. CTFrameGetLineOrigins(ctFrame, CFRangeMake(0, 0), lineOrigins);
  29. //遍历每一个CTline
  30. for (int i = 0; i < CFArrayGetCount(lines); i++) {
  31. CTLineRef line = CFArrayGetValueAtIndex(lines, i);
  32. CGFloat lineAscent;
  33. CGFloat lineDescent;
  34. CGFloat lineLeading;
  35. CTLineGetTypographicBounds(line, &lineAscent, &lineDescent, &lineLeading);
  36. CFArrayRef runs = CTLineGetGlyphRuns(line);
  37. //遍历每一个CTRunRef
  38. for (int j = 0; j < CFArrayGetCount(runs); j++) {
  39. CGPoint lineOrigin = lineOrigins[i];
  40. CTRunRef run = CFArrayGetValueAtIndex(runs, j);
  41. NSDictionary* attributes = (NSDictionary*)CTRunGetAttributes(run);
  42. const CGPoint *point=CTRunGetPositionsPtr(run);
  43. NSString *attributeName = [attributes objectForKey:@"FTCoreTextDataName"];
  44. if ([attributeName isEqualToString:@"input"]) {
  45. //添加输入框
  46. if (createObjectMode) {
  47. UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(point[0].x+7, self.frame.size.height-lineOrigin.y-14, 150.0f, 20.0f)];
  48. [textField setBorderStyle:UITextBorderStyleNone]; //外框类型
  49. textField.placeholder = @""; //默认显示的字
  50. textField.font=[UIFont fontWithName:@"TimesNewRomanPSMT" size:12.f];
  51. textField.textColor=[UIColor blueColor];
  52. [self addSubview:textField];
  53. // 为UITextView关联响应事件
  54. [self.delegate addCoreTextViewObject:textField type:@"input"];
  55. }else{
  56. CGRect frame=CGRectMake(point[0].x+7, self.frame.size.height-lineOrigin.y-14, 150.0f, 20.0f);
  57. [self.delegate resetObjectFrame:frame type:@"input"];
  58. }
  59. }else if ([attributeName isEqualToString:@"button"]){
  60. //添加按钮
  61. if (createObjectMode) {
  62. UIButton *button =[[UIButton alloc]initWithFrame:CGRectMake(point[0].x-5, self.frame.size.height-lineOrigin.y-16, 250, 22.0f)];
  63. UIColor *ucolor=[UIColor lightGrayColor];
  64. [button.layer setMasksToBounds:YES];
  65. [button.layer setCornerRadius:7.0]; //设置矩圆角半径
  66. [button.layer setBorderWidth:1.0]; //边框宽度
  67. [button.layer setBorderColor:ucolor.CGColor];//边框颜色
  68. [self addSubview:button];
  69. // 为UIButton关联响应事件
  70. [self.delegate addCoreTextViewObject:button type:@"button"];
  71. }else{
  72. CGRect frame=CGRectMake(point[0].x-5, self.frame.size.height-lineOrigin.y-16, 250, 22.0f);
  73. [self.delegate resetObjectFrame:frame type:@"button"];
  74. }
  75. }
  76. }
  77. }
  78. if (createObjectMode){
  79. createObjectMode=NO;
  80. }
  81. CFRelease(ctFrame);
  82. CFRelease(path);
  83. CFRelease(ctFramesetter);
  84. }




声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/729160
推荐阅读
相关标签
  

闽ICP备14008679号