这段时间在搞电子书,把这些天出现的问题归总下,我还是希望电子书的格式包括返回的数据,可直观的反应出客户端想表达的内容;原生的体验还是比较好的,希望对coretext再深入。

1.判断点击的位置是否在某个NSRange范围内

#pragma mark 判断点击的位置是否在 range内
/**将点击的位置转换成字符串的偏移量,如果没有找到,则返回-1view:viewpoint:点击位置frameRef:当前view的frameRef*/
+ (CFIndex)wkj_touchContentOffsetInView:(UIView *)viewpoint:(CGPoint)pointframeRef:(CTFrameRef)frameRef{CTFrameRef textFrame = frameRef;CFArrayRef lines = CTFrameGetLines(textFrame);if (!lines) {return -1;}CFIndex count = CFArrayGetCount(lines);// 获得每一行的origin坐标
    CGPoint origins[count];CTFrameGetLineOrigins(textFrame, CFRangeMake(0,0), origins);// 翻转坐标系CGAffineTransform transform =  CGAffineTransformMakeTranslation(0, view.bounds.size.height);transform = CGAffineTransformScale(transform, 1.f, -1.f);CFIndex idx = -1;for (int i = 0; i < count; i++) {CGPoint linePoint = origins[i];CTLineRef line = CFArrayGetValueAtIndex(lines, i);// 获得每一行的CGRect信息CGRect flippedRect = [self wkj_getLineBounds:line point:linePoint];CGRect rect = CGRectApplyAffineTransform(flippedRect, transform);if (CGRectContainsPoint(rect, point)) {// 将点击的坐标转换成相对于当前行的坐标cocoapodsCGPoint relativePoint = CGPointMake(point.x-CGRectGetMinX(rect),point.y-CGRectGetMinY(rect));// 获得当前点击坐标对应的字符串偏移idx = CTLineGetStringIndexForPosition(line, relativePoint);}}return idx;
}+ (CGRect)wkj_getLineBounds:(CTLineRef)line point:(CGPoint)point {CGFloat ascent = 0.0f;CGFloat descent = 0.0f;CGFloat leading = 0.0f;CGFloat width = (CGFloat)CTLineGetTypographicBounds(line, &ascent, &descent, &leading);CGFloat height = ascent + descent;return CGRectMake(point.x, point.y - descent, width, height);
}/**此处判断根据上面返回的字符串的偏移量,对比range是否在点击的位置*/
+ (BOOL)wkj_judgeAtIndex:(CFIndex)index range:(NSRange)range {if (NSLocationInRange(index, range)) {///点击处在range内return YES;}return NO;
}

2.通过CFRange与CTFrameRef获取要操作(涂色,划线)的CGRect数组

#pragma mark 通过range获取rect集合【用于划线、涂色】
+ (NSArray*)wkj_frameGetFrameOfStringInRange:(CTFrameRef)frameRef range:(CFRange)range{CFRange frameRefRange = CTFrameGetStringRange(frameRef);range = [self wkj_cfRangeInsection:frameRefRange range:range];if ([self wkj_cfRangeEqualToRange:range range:CFRangeZero]) {return nil;}NSArray *lines = (NSArray*)CTFrameGetLines(frameRef);NSInteger lineCount = [lines count];//获取整个CTFrame的大小CGPathRef path = CTFrameGetPath(frameRef);CGRect frameRefRect = CGPathGetBoundingBox(path);//获取所有行的起点CGPoint *origins = (CGPoint*)malloc(lineCount * sizeof(CGPoint));CTFrameGetLineOrigins(frameRef, CFRangeMake(0, 0), origins);NSMutableArray *rects = [NSMutableArray array];for (CFIndex index = 0; index<lines.count; index++) {CTLineRef line = (__bridge CTLineRef)[lines objectAtIndex:index];CFRange rangeOfLine = CTLineGetStringRange(line);CFRange rangeOfInsection = [self wkj_cfRangeInsection:rangeOfLine range:range];if (![self wkj_cfRangeEqualToRange:rangeOfInsection range:CFRangeZero]) {CGRect frame = [self wkj_lineGetFrame:line point:origins[index] range:rangeOfInsection];frame = CGRectOffset(frame, frameRefRect.origin.x, frameRefRect.origin.y);[rects addObject:[NSValue valueWithCGRect:frame]];}}free(origins);return [rects copy];
}+ (CGRect)wkj_lineGetFrame:(CTLineRef)linepoint:(CGPoint)originrange:(CFRange)range{CFRange lineRange = CTLineGetStringRange(line);range = [self wkj_cfRangeInsection:lineRange range:range];CGFloat trailingWhitespaceWidth = CTLineGetTrailingWhitespaceWidth(line);if ([self wkj_cfRangeGetEndLocation:range]==[self wkj_cfRangeGetEndLocation:lineRange]&&trailingWhitespaceWidth>0) {--range.length;}CGFloat xStart = CTLineGetOffsetForStringIndex(line, range.location, NULL);CGFloat xEnd = CTLineGetOffsetForStringIndex(line, [self wkj_cfRangeGetEndLocation:range]+1, NULL);CGFloat ascent, descent, leading;CTLineGetTypographicBounds(line, &ascent, &descent, &leading);CGRect selectionRect = CGRectMake(origin.x + xStart,origin.y - descent,xEnd - xStart,ascent + descent + leading);return selectionRect;
}+ (CFRange)wkj_cfRangeInsection:(CFRange)range1 range:(CFRange)range2{if ([self wkj_cfRangeGreaterThanRange:range1 range:range2]||[self wkj_cfRangeGreaterThanRange:range2 range:range1]) {return CFRangeZero;}CFIndex beginLocation = MAX(range1.location, range2.location);CFIndex endLocation = MIN([self wkj_cfRangeGetEndLocation:range1], [self wkj_cfRangeGetEndLocation:range2]);return [self wkj_cfRangeMakeWithInterval:beginLocation endIndex:endLocation];
}+ (BOOL)wkj_cfRangeGreaterThanRange:(CFRange)range1 range:(CFRange)range2{return range1.location>[self wkj_cfRangeGetEndLocation:range2];
}
+ (CFIndex)wkj_cfRangeGetEndLocation:(CFRange)range{return range.location+range.length-1;
}
+ (CFRange)wkj_cfRangeMakeWithInterval:(CFIndex)startIndex endIndex:(CFIndex)endIndex{return CFRangeMake(startIndex, endIndex - startIndex + 1);
}
+ (BOOL)wkj_cfRangeEqualToRange:(CFRange)range1 range:(CFRange)range2{return range1.location == range2.location&&range1.length==range2.length;
}

3.涂色划线

- (void)wkj_drawLineForSelectArea{CGContextRef context = UIGraphicsGetCurrentContext();CGContextSetFillColorWithColor(context, [[UIColor redColor] colorWithAlphaComponent:0.3].CGColor);for (NSValue *rectValue in _arraySelectRect) {CGRect rect = [rectValue CGRectValue];rect.origin.y -= 2.5;///划线时可设置高度为1  涂色是可根据字体大小设置rect.size.height = 1;rect.size.width -= 1.5;CGContextFillRect(context, rect);}
}

4.CoreText 分页

#pragma mark 分页
/**CoreText 分页str: NSAttributedString属性字符串textFrame: 绘制区域*/+ (NSArray *)wkj_coreTextPaging:(NSAttributedString *)str textArea:(CGRect)textFrame{///分页NSAttributedString结果
    // NSMutableArray *arrayPagingStr = [NSMutableArray array];///分页NSRange结果NSMutableArray *arrayPagingRange = [NSMutableArray array];CFAttributedStringRef cfStrRef = (__bridge CFAttributedStringRef)str;CTFramesetterRef framesetterRef = CTFramesetterCreateWithAttributedString(cfStrRef);CGPathRef path = CGPathCreateWithRect(textFrame, NULL);int textPos = 0;NSUInteger strLength = [str length];while (textPos < strLength)  {//设置路径CTFrameRef frame = CTFramesetterCreateFrame(framesetterRef, CFRangeMake(textPos, 0), path, NULL);CFRange frameRange = CTFrameGetVisibleStringRange(frame);NSRange range = NSMakeRange(frameRange.location, frameRange.length);[arrayPagingRange addObject:[NSValue valueWithRange:range]];
        // [arrayPagingStr addObject:[str attributedSubstringFromRange:range]];//移动textPos += frameRange.length;CFRelease(frame);}CGPathRelease(path);CFRelease(framesetterRef);
    // return arrayPagingStr;return arrayPagingRange;
}

5.获取绘制区域的高度

/**str:NSAttributedString 内容属性width: 绘制的宽度*/
+ (CGFloat)coretextContentHeight:(NSAttributedString *)str width:(CGFloat)width{//创建CTFramesetterRefCTFramesetterRef framesetterRef = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)str);// 获得要绘制的区域高度CGSize restrictSize = CGSizeMake(width, CGFLOAT_MAX);CGSize coreTextSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetterRef, CFRangeMake(0,0), nil, restrictSize, nil);return coreTextSize.height;
}

项目笔记

#import "BookDataTool.h"
#import "CoreTextDataModel.h"@implementation BookDataTool/**CoreText 分页str: NSAttributedString属性字符串textFrame: 绘制区域*/+ (NSArray *)wkj_coreTextPaging:(NSAttributedString *)strtextArea:(CGRect)textFrame{
//    textFrame.size.height = textFrame.size.height;///分页NSAttributedString结果//    NSMutableArray *arrayPagingStr = [NSMutableArray array];///分页NSRange结果NSMutableArray *arrayCoretext = [NSMutableArray array];CFAttributedStringRef cfStrRef = (__bridge CFAttributedStringRef)str;CTFramesetterRef framesetterRef = CTFramesetterCreateWithAttributedString(cfStrRef);CGPathRef path = CGPathCreateWithRect(textFrame, NULL);int textPos = 0;NSUInteger strLength = [str length];while (textPos < strLength)  {//设置路径CTFrameRef frame = CTFramesetterCreateFrame(framesetterRef, CFRangeMake(textPos, 0), path, NULL);CFRange frameRange = CTFrameGetVisibleStringRange(frame);NSRange range = NSMakeRange(frameRange.location, frameRange.length);//        [arrayPagingRange addObject:[NSValue valueWithRange:range]];//        [arrayPagingStr addObject:[str attributedSubstringFromRange:range]];
        CoreTextDataModel *model = [[CoreTextDataModel alloc]init];model.ctFrame = frame;model.range = range;model.content = [str attributedSubstringFromRange:range];[arrayCoretext addObject:model];//移动textPos += frameRange.length;CFRelease(frame);}CGPathRelease(path);CFRelease(framesetterRef);//    return arrayPagingStr;return arrayCoretext;
}///获取属性字符串
+ (NSAttributedString *)wkj_loadTemplateFile:(NSString *)path{NSMutableAttributedString *resultAtt = [[NSMutableAttributedString alloc] init];NSData *data = [NSData dataWithContentsOfFile:path];if (data) {NSArray *array = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];if ([array isKindOfClass:[NSArray class]]) {for (NSDictionary *dic in array) {if ([dic[@"type"] isEqualToString:@"txt"]) {NSAttributedString *att = [self parseAttributedContentFromDictionary:dic];[resultAtt appendAttributedString:att];}}}}return resultAtt;
}
///获取属性字符串
+ (NSAttributedString *)parseAttributedContentFromDictionary:(NSDictionary *)dict{NSMutableDictionary *attributes = [self attributes];if ([dict[@"type1"] isEqualToString:@"0"]) {CTFontRef fontRef = CTFontCreateWithName((CFStringRef)@"ArialMT", 35, NULL);attributes[(id)kCTFontAttributeName] = (__bridge id)fontRef;CFRelease(fontRef);}NSString *content = dict[@"content"];return [[NSAttributedString alloc] initWithString:content attributes:attributes];
}
///获取属性字符串字典
+ (NSMutableDictionary *)attributes{CGFloat fontSize = [BookThemeManager sharedManager].fontSize;CTFontRef fontRef = CTFontCreateWithName((CFStringRef)@"ArialMT", fontSize, NULL);CGFloat lineSpacing = [BookThemeManager sharedManager].lineSpace;const CFIndex kNumberOfSettings = 3;CTParagraphStyleSetting theSettings[kNumberOfSettings] = {{ kCTParagraphStyleSpecifierLineSpacingAdjustment, sizeof(CGFloat), &lineSpacing },{ kCTParagraphStyleSpecifierMaximumLineSpacing, sizeof(CGFloat), &lineSpacing },{ kCTParagraphStyleSpecifierMinimumLineSpacing, sizeof(CGFloat), &lineSpacing }};CTParagraphStyleRef theParagraphRef = CTParagraphStyleCreate(theSettings, kNumberOfSettings);UIColor * textColor = [BookThemeManager sharedManager].textColor;NSMutableDictionary * dict = [NSMutableDictionary dictionary];dict[(id)kCTForegroundColorAttributeName] = (id)textColor.CGColor;dict[(id)kCTFontAttributeName] = (__bridge id)fontRef;dict[(id)kCTParagraphStyleAttributeName] = (__bridge id)theParagraphRef;CFRelease(theParagraphRef);CFRelease(fontRef);return dict;
}@end

转载于:https://www.cnblogs.com/wangkejia/p/8321102.html

iOS-CoreText的那些事【电子书的那些事】相关推荐

  1. 毕业季·大学最遗憾的事/没有完成的事?

    活动地址:毕业季·进击的技术er 夏日炎炎,热浪中我们迎来毕业季,这是告别,也是迈向新起点的开始,CSDN诚邀各毕业生/在校生/职场人讲述自己的毕业季故事,分享自己的经验,技术er的进击之路. 毕业生 ...

  2. 沙发摆放7大害人风水 破财事小伤身事大(组图)

    沙发摆放7大害人风水 破财事小伤身事大(组图) 2012-09-12 13:50 来源: 网文 (网络图片/看中国配图) 沙发是客厅中日常用来休息.闲谈及会客的家具,在客厅中处于非常重要的地位.因此, ...

  3. PHP爬取糗事百科首页糗事

    突然想获取一些网上的数据来玩玩,因为有SAE的MySql数据库,让它在那呆着没有什么卵用!于是就开始用PHP编写一个爬取糗事百科首页糗事的小程序,数据都保存在MySql中,岂不是很好玩! 说干就干!首 ...

  4. 钢琴家软件里曲谱的数据为什么更新不了_王者荣耀安卓与IOS互通?IOS恐怕得到不少利益,不然这事成不了...

    铁铁们,我是帅气呆萌的悠鱼(>_ 排位结束后.队友.对手的战绩很好,或者是很坑,你想要点开他的主页看看他是何方神圣,但是却看不了,给你提示,不是同一个系统,是看不了人家资料.相信很多人在打排位时 ...

  5. iOS开发三方资源 - 欲先攻其事必先利其器

    一:源代码实例 1:快速搭建项目源代码 地址:https://github.com/wujunyang/MobileProject MobileProject项目是一个以MVC模式搭建的开源功能集合, ...

  6. iOS 应用安全权威指南电子书 PDF 分享

    目录 推荐序 V 译者序 VII 作者简介 IX 前言 XI 致谢 XXI 第一部分 iOS 基础 第1 章 iOS 安全模型 2 安全启动 3 沙盒机制 3 数据保护和全盘加密 4 加密密钥的层级 ...

  7. iOS APP上传应用市场的哪些事(一)?

    1.关于应用上传的预览图的新规? 最近苹果对于新提交审核的产品,都加了6.5尺寸预览图的添加.在之前,只用5.5的尺寸就可以了,现在 苹果要求,6.5 和5.5 都是必须的提供图片了,所以大家注意了. ...

  8. IOS CoreText.framework --- 基本用法

    API接口文档. https://developer.apple.com/library/mac/#documentation/Carbon/Reference/CoreText_Framework_ ...

  9. IOS上路_07-简单示例-电子书

    2019独角兽企业重金招聘Python工程师标准>>> 1.定义一个阅读器: 2.在视图中加入TextView控件: 3.配置阅读器: 4.测试: - end 转载于:https:/ ...

  10. 从“删库跑路”这件事聊聊数据安全那些事

    最近有个删库跑路的帖子在网上引起热议,很多企业管理者都开始担忧数据库的安全可靠性.其实是数据库安全和备份机制没做到位,如果一开始就采用严密的安全机制和完善的数据库备份机制,那么即便是误删了数据库也可以 ...

最新文章

  1. SQL中Group By的使用详解
  2. oracle的管理工具
  3. 在Linux系统里安装Virtual Box的详细步骤
  4. OPENSSL ENGINE机制
  5. 问题 1051: [编程入门]结构体之成绩统计2
  6. typescript mongodb 教程搜集
  7. Bootstarp4 列表组
  8. Unity Editor自制工具(1)--“Editor目录栏按钮+全局搜索方法+自制Editor窗口”实现搜索与删除场景中任意名称游戏物体
  9. [导入]视频游戏开发系列课程(8):开始创造游戏的“精灵”的行为.zip(14.93 MB)
  10. Android常见界面控件(基础入门)
  11. SOLIDWORKS软件二十四年来的进化发展史
  12. 走进“开源SDR实验室” 一起玩转4G/5G开源项目srsRAN(srsLTE升级版):安装方法+NB-IoT测试
  13. QQ群霸屏技术教程:不论霸屏技术,只谈QQ认证群
  14. 怎样学好Python
  15. android aar管理,android 库依赖管理之一aar依赖
  16. python小游戏——猜单词游戏(Hangman)
  17. 【09年特长生第四题】开发区规划
  18. 局域网流量监控软件以及其实现方式
  19. matlab读mif文件,MATLAB将mif文件转换成coe文件(原创)
  20. Linux命令之screen命令

热门文章

  1. python 怎么注释_python的代码怎么写注释
  2. matlab在振动信号处理中的应用_激光测振仪在超声变幅杆振动测试中的应用
  3. adb命令连接模拟器,could not read ok from ADB Server
  4. 安装虚拟机(二)配置静态ip
  5. 【渝粤教育】国家开放大学2018年春季 3818-21T燃气工程施工 参考试题
  6. 应用机器学习(六):决策树
  7. 约束最优化方法 (四) 乘子法
  8. vue-cli 可视化工具
  9. 【转载】Sqlserver使用Convert函数进行数据类型转换
  10. 设计模式12——代理模式