赞
踩
http://blog.csdn.net/jymn_chen/article/details/10191101
在学习了iOS7新出的Text Kit的基础知识后,开始着手编写基于Text Kit的电子书阅读器程序。
首先是搭建程序的基本结构:RootView(导航视图)——BookListView(书本目录表视图)——ReadingView(阅读视图)——URLInteractionView(网页浏览视图)。
其中ReadingView是核心视图,几乎所有的阅读都在该页面中展开。
目前有很多电子书阅读器应用,大多数都有非常棒的翻页效果功能,而且,如果文本非常的长,用户只能通过滚动条来浏览电子书,这样的用户体验不好。所以我打算做成带翻页效果的阅读界面。
明显,翻页效果基于电子书分页,所以首先要进行电子书分页。
其实在iOS提供的sdk中就提供了UIPageViewController这个类来提供动态的翻页效果,但是在配置datasource时,必须静态配置好每一页的数据和总页数等,这种做法略显不够灵。而且我对该类的使用也不够熟悉,加上我想自己尝试去写出翻页效果的实现,最后我放弃了使用UIPageViewController。
(一)电子书分页
开始的分页方案是先计算文本总长度,然后设定一个每页字符数的标准,从而计算出总页数以及得出每页显示的文字及其范围。但是每页字符数的标准很难定下来,于是参考网上的文章进行了改进:http://mobile.51cto.com/iphone-227245.htm
该网页提供的参考代码如下:
在下面翻页时只需直接在referCharatersPerPage中取得文本范围并加载就可以了。
的确,这样的分页效果非常好,每一页的文字都刚好布满整个textview,页与页之间的连贯性非常好,而且在翻页时获取指定页的文本范围非常的简单。但是非常糟糕的是这种分页算法的效率可谓奇低,例如对一篇最后分成4页的文本要几秒,对一篇分成200多页的文本可能要几分钟。另外,为了存储rangeOfPages,需要申请预定的内存空间,这又进一步增大了程序的开销。
尽管如此,该算法的思想还是可取的。
下面是我的分页的代码:
对比之前的算法,由于不需要预先申请存储页面范围的内存空间,所以系统开销减小。更重要的是分页所需的时间大大减小。
使用也是非常简便,而且不需预先申请空间保存各页面的范围:
不足之处:
1.对于近80000字符数的文本的加载可能也需要3秒左右时间加载,明显不够快,在此我的进一步改进的设想是将首次加载文本时时计算好的charsPerPage和对应的电子书名保存起来,在下次加载时直接从保存好的数据中加载charsPerPage,这样非首次加载文本就可以免去分页计算的时间。但是我还没想好用哪种方法保存数据,有待改进。
2.最大的不足是由于限定了每页的字符数,所以难免会出现每页的显示会出现参差不齐,例如每页显示的文本高度不同,页与页之间的连贯性不够好,等等。
3.sizeWithFont:constrainedToSize:lineBreakMode:方法已经被iOS 7.0建议Deprecated。
可以用iOS7新出的方法来代替:
(二)字体调整
若用户在Settings中调整字体时,text view中的字体要作出相应的变化。
其实也非常简单,首先在消息中心注册消息接受者:
由于preferredFont_是私有变量,可以在整个.m文件中实现,所以在以上的实现方法中可以设定preferredFont_为调整后的字体。
为了制造翻页效果,所以我将PageView和ReadingViewController独立开来,ReadingViewController在self.view中加入PageView来实现多个页面视图的加载。
首先看看PageView的接口部分:
然后是实现部分的初始化方法:
再看看ReadingViewController的viewDidLoad方法部分代码:
为了翻页效果根据用户的手势触点动态变化,需要在以下方法中实现:
接着是触摸移动:
这样一来,翻转页面的宽度在160到320之间非线性缓慢增大至160,在0到160之间线性增大320(超出视图左边的部分我们看不见)。
为了制造页面翻转的效果,要添加两个CAGradientLayer:shadow和margin。如下:
shadow用于展示阴影效果(Tag页面右边缘),margin用于展示页边效果(Tag页面左边缘):
为了防止触摸移动过程中的layer停留在页面中,首先要移除视图中的layer:
如果是翻向下一页,那么视图及layer的叠放次序(由下至上)为:
self.view,addPageView,curPageView,backPageView(Tag标识页面),margin,shadow。
如果是翻向上一页,那么视图及layer的叠放次序(由下至上)为:
self.view,curPageView,addPageView,backPageView,margin,shadow。
注意一定要设置好各个视图的clipToBounds属性为YES,防止遮住下层视图:
触摸结束后首先判断触摸的移动距离是否超过最小移动距离:self.view.frame.width / 5,,如果没有达到则不接受手势,否则翻页成功并加载下一页的内容在curPageView中,移除addPageView和所有layer。
在这里要注意一个问题:由于UITextView无法响应UITouch对象的触摸事件,只有UIView可以响应UITocuh对象的触摸,所以以上基于touchesBegan:,touchesMoved:和touchesEnded:来制造翻页效果的方法只能适用于普通的UIView,UIImageView,UILabel等,而不能用于UITextView,也就是说如果text view铺满整个curPageView,那么将无法响应touch事件的方法,而且为了美观起见,我设定text view的区域范围为:
另外为了扩大touch响应的范围,我又在视图的左右边缘加入了两个标签:
记住设置标签的userInteractionEnabled属性为YES就可以了。
标签的action的作用是若工具条出现,轻击标签就可以让工具条隐藏。
另外,若对文字进行编辑则隐藏这两个标签。
对于制造翻页效果,简单来说就是在self.view中按特定的叠加关系添加几个视图和layer,并根据touch的x值来设置视图的位置,从而制造翻页的效果。
(四)页面跳转,书签
为了实现快速的页面跳转,可以唤出带输入框的对话框:
(五)ReadingViewController的几个工具条和标签
界面:
代码:
(六)响应网络链接
主要就是实现UITextViewDelegate中的方法:
(七)使用NSTextStorage设置和修改文本的属性
另外我独立写了一个UITextStorage的子类TextStorage,要使用该类去修改文本的属性也非常简单,可以参见我之前写的TextKit学习(三)。
由于程序还有很多要修改的地方,而且还有许多功能可以扩展,所以暂时不上传资源来对比看看。我会继续努力改进程序并且扩展功能的,到时再上个资源来分享交流。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。