解决NSTextContainer分页时文本截断问题
解决NSTextContainer分页时文本截断问题

NSTextContainer与NSLayoutManager配合使用可以将大文本文件分页,但是,分页过程中会遇到问题,显示字符被截断的问题:)
- (void)viewDidLoad
{
[super viewDidLoad]; // 数据源
NSString *string = [NSString stringWithContentsOfURL:[NSBundle.mainBundle URLForResource:@"bubizhidaowoshishui" withExtension:@"txt"] usedEncoding:nil
error:nil]; // 文本容器
NSTextStorage *storage = [[NSTextStorage alloc] initWithString:string]; // 文本容器的布局管理器
NSLayoutManager *layoutManager = [NSLayoutManager new];
[storage addLayoutManager:layoutManager]; // 分段显示文本容器中的内容
CGSize size = CGSizeMake(, );
NSTextContainer *textContainer1 = [[NSTextContainer alloc] initWithSize:size];
[layoutManager addTextContainer:textContainer1]; NSTextContainer *textContainer2 = [[NSTextContainer alloc] initWithSize:size];
[layoutManager addTextContainer:textContainer2]; NSTextContainer *textContainer3 = [[NSTextContainer alloc] initWithSize:size];
[layoutManager addTextContainer:textContainer3]; UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(, ,
size.width,
size.height)
textContainer:textContainer3]; textView.layer.borderWidth = ;
textView.scrollEnabled = NO;
textView.editable = NO;
[self.view addSubview:textView];
}
以下是我的运行结果(注意看底下红色的部分,文本被截断了哦):

为什么会被截断呢,按理说,NSLayoutManager会计算好一个size值然后给NSTextContainer让这个NSTextContainer自己适应的.
苹果官方文档里面有描述:
Generating Line Fragment Rectangles
The layout manager lays text within an NSTextContainer object in lines of glyphs. The layout of these lines within the text container is determined by its shape and by any exclusion paths it contains. Wherever the line fragment rectangle intersects a region defined by an exclusion path, the lines in those parts must be shortened or fragmented; if there’s a gap across the entire region, the lines that would overlap it have to be shifted to compensate.
The layout manager proposes a rectangle for a given line and then asks the text container to adjust the rectangle to fit. The proposed rectangle usually spans the text container’s bounding rectangle, but it can be narrower or wider, and it can also lie partially or completely outside the bounding rectangle. The message that the layout manager sends the text container to adjust the proposed rectangle is lineFragmentRectForProposedRect:atIndex:writingDirection:remainingRect:, which returns the largest rectangle available for the proposed rectangle, based on the direction in which text is laid out. It also returns a rectangle containing any remaining space, such as the space left on the other side of a hole or gap in the text container.
The layout manager makes one final adjustment when it actually fits text into the rectangle. This adjustment is a small amount fixed by the text container, called the line fragment padding, which defines the portion on each end of the line fragment rectangle left blank. Text is inset within the line fragment rectangle by this amount (the rectangle itself is unaffected). Padding allows for small-scale adjustment of the text container’s region at the edges (and around any holes) and keeps text from directly abutting any other graphics displayed near the region. You can change the padding from its default value with the lineFragmentPadding property. Note that line fragment padding isn’t a suitable means for expressing margins. For document margins, you should set the UITextView object’s position and size within its enclosing view. And for text margins, you should set the textContainerInset property of the text view. In addition, you can set indentation values for individual paragraphs using NSMutableParagraphStyle properties such as headIndent.
In addition to returning the line fragment rectangle itself, the layout manager returns a rectangle called the used rectangle. This is the portion of the line fragment rectangle that actually contains glyphs or other marks to be drawn. By convention, both rectangles include the line fragment padding and the interline space (which is calculated from the font’s line height metrics and the paragraph’s line spacing parameters). However, the paragraph spacing (before and after) and any space added around the text, such as that caused by center-spaced text, are included only in the line fragment rectangle, and are not included in the used rectangle.
每个NSTextContainer的frame值都是被NSLayoutManager粗略计算过的,与你设置NSTextContainer的size值略有出入,有时候大些,有时候小些,但误差绝度不会超过一个字符的高度.所以,苹果建议我们在设置UITextView的时候,给这个NSTextContainer预留一定的高度......
解决的方法如下:

效果如下:

这个问题有这么棘手么?其实,我是在黔驴技穷的情况下(github上下载了7-8个相关demo,stackoverflow上搜寻等等途径都无效的情况下)细致研究官方提供的pdf文档才明白过来的:),你懂的.
附录:
使用自定义字体不是梦:)

- (void)viewDidLoad
{
[super viewDidLoad]; // 数据源
NSString *string = [NSString stringWithContentsOfURL:[NSBundle.mainBundle URLForResource:@"bubizhidaowoshishui" withExtension:@"txt"] usedEncoding:nil
error:nil]; // 文本容器
NSTextStorage *storage = [[NSTextStorage alloc] initWithString:string]; // 文本容器的布局管理器
NSLayoutManager *layoutManager = [NSLayoutManager new];
[storage addLayoutManager:layoutManager]; // 段落属性
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.lineHeightMultiple = .f; // 可变行高,乘因数
paragraphStyle.lineSpacing = .f; // 行间距
paragraphStyle.minimumLineHeight = .f; // 最小行高
paragraphStyle.maximumLineHeight = .f; // 最大行高
paragraphStyle.paragraphSpacing = .f; // 段间距
paragraphStyle.alignment = NSTextAlignmentLeft; // 对齐方式
paragraphStyle.firstLineHeadIndent = .f; // 段落首文字离边缘间距
paragraphStyle.headIndent = .f; // 段落除了第一行的其他文字离边缘间距
paragraphStyle.tailIndent = .f; // ???????
[storage addAttribute:NSParagraphStyleAttributeName
value:paragraphStyle
range:NSMakeRange(, storage.string.length)]; // 字体属性
[storage addAttribute:NSFontAttributeName
value:[UIFont fontWithName:CUSTOM_FONT(@"新蒂小丸子体", ) size:.f]
range:NSMakeRange(, storage.string.length)]; [storage addAttribute:NSForegroundColorAttributeName
value:[UIColor redColor]
range:NSMakeRange(, storage.string.length)]; // 分段显示文本容器中的内容
CGSize size = CGSizeMake(, );
NSTextContainer *textContainer1 = [[NSTextContainer alloc] initWithSize:size];
[layoutManager addTextContainer:textContainer1]; NSTextContainer *textContainer2 = [[NSTextContainer alloc] initWithSize:size];
[layoutManager addTextContainer:textContainer2]; NSTextContainer *textContainer3 = [[NSTextContainer alloc] initWithSize:size];
[layoutManager addTextContainer:textContainer3]; UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(, ,
size.width,
size.height + )
textContainer:textContainer3]; textView.layer.borderWidth = ;
textView.scrollEnabled = NO;
textView.editable = NO;
[self.view addSubview:textView];
}
解决NSTextContainer分页时文本截断问题的更多相关文章
- 解决java socket在传输汉字时出现截断导致乱码的问题
解决java socket在传输汉字时出现截断导致乱码的问题 当使用socket进行TCP数据传输时,传输的字符串会编码成字节数组,当采用utf8编码时,数字与字母长度为1个字节,而汉字一般为3个字节 ...
- 关于使用视图进行分页时出现当前记录集不支持书签的错误解决方法及原因(asp)
一般在使用视图进行查询时,视图中意般都关联了两个或者更多个表,一般在这种情况下才会使用视图,但是但我在使用视图来查询数据时没有问题,但是一旦在分页中使用到视图进行查询就会出现错误提示如下: ADODB ...
- [Erlang 0107] Erlang实现文本截断
抽时间处理一下之前积压的一些笔记.前段时间有网友 @稻草人 问字符串截断的问题"各位大侠 erlang截取字符串一般用哪个函数啊",有人支招用string:substr/3, ...
- php--如何解决网站分页导致的SEO问题
如何解决网站分页导致的SEO问题 分页(pagination)是一种自动分页机制,可以将移动Web窗体中的内容分割成一组组较小的页进行呈现,以适合于特定的设备,该机制还呈现可用于浏览到其他页的用户界面 ...
- 解决 MySQL 分页数据错乱重复
前言 一天,小明兴匆匆的在通讯工具上说:这边线上出现了个奇怪的问题,麻烦 DBA 大大鉴定下,执行语句 select xx from table_name wheere xxx order by 字段 ...
- postgresql排序分页时数据重复问题
当同时排序又分页时,如果排序的字段X不是唯一字段,当多个记录的X字段有同一个值时顺序是随机的. 这个有可能造成分页时数据重复的问题.某一页又把上一页的数据查出来了,其实数据库只有一条记录. 解决办法: ...
- ES scroll(ES游标) 解决深分页
ES scroll(ES游标) 解决深分页. Why 当Elasticsearch响应请求时,它必须确定docs的顺序,排列响应结果.如果请求的页数较少(假设每页20个docs), Elasticse ...
- 解决Gradle编译时出现: 编码GBK的不可映射字符
解决Gradle编译时出现: 编码GBK的不可映射字符 在build.gradle文件中加入如下内容: [compileJava, compileTestJava]*.options*.encodin ...
- SpringMVC学习系列-后记 解决GET请求时中文乱码的问题
SpringMVC学习系列-后记 解决GET请求时中文乱码的问题 之前项目中的web.xml中的编码设置: <filter> <filter-name>CharacterEnc ...
随机推荐
- centos6.5 + 7 静态ip配置
2017/09/19日更, centos6.5 可用 DEVICE=eth0 TYPE=Ethernet ONBOOT=yes NM_CONTROLLED=yes BOOTPROTO=static D ...
- onclick时间加return和不加return的区别
JAVASCRIPT在事件中调用函数时用return返回值实际上是对window.event.returnvalue进行设置. 而该值决定了当前操作是否继续.当返回的是true时,将继续操作.当返回是 ...
- Oracle 12c 建表空间语句
create tablespace TBS_DYS datafile 'D:/Oracle_12c/app/dingyingsi/oradata/dingyingsi/TBS_DYS.ba' size ...
- Java Date SimpleDateFormat
public static void main(String[] args) { long millis = 1492741275301L; Calendar calendar = Calendar. ...
- Android 控件:使用下拉列表框--Spinner
---恢复内容开始--- 一.前段代码 <Spinner android:id="@+id/spin" android:paddingTop="10px" ...
- Oracle.DataAccess.Client.OracleConnection.Open()报错System. NullReferenceException
使用ODAC链接Oracle数据库时,conn.Open()报错:未将对象的实例设置到对象引用. Oracle.DataAccess.dll版本:4.121.2.0 ODAC RELEASE 4 Or ...
- Visual Studio 2017 系统发布部署服务器教程
Visual Studio 2017 系统发布部署服务器教程 一.公司网站部署 --- 第一档 _Visual Studio 2017 发布网站系统教程 二.公司网站部署 --- 第二档 ...
- CentOS 忘记root密码(重置root密码)
首先开机选择Advanced options for ****这一行按回车: 然后选中最后是(recovery mode)这一行按"E"进入编辑页面: 将ro recovery改为 ...
- 14、通过jpa往数据库插数据
这是接着上一篇写的,在上一篇的基础上添加 Controller @RestController public class HelloController { @Resource private Hel ...
- 百度Ueditor编辑器
百度的Ueditor编辑器出于安全性考虑,用户在html模式下粘贴进去的html文档会自动被去除样式和转义.虽然安全的,但是非常不方便. 1. ueditor.config.js 做出如下修改即可: ...