美文网首页Android 知识Android收藏集Android
空手撸一个Android阅读器,无第三方支持

空手撸一个Android阅读器,无第三方支持

作者: s1991721 | 来源:发表于2018-10-05 13:58 被阅读618次

    开篇


    几个月前,晚上梦到在研究翻页动画,次日上班居然想起了昨天晚上的梦。search了相关信息,大概要用到数学计算、canvas绘图等相关内容。对我来说手动绘图这方面的实践还是0,想想短时间内应该搞不定,便将此事记在了待做清单内。(公司电脑一个单子,自己Mac一个单子,增加行数的速度远比删除的速度快。)

    十一长假前夕手头没什么事情,看着清单顶部的第一项(时间排序),便照着例文开始绘图。画到后面,想想就一张图片多无聊。算了!加点功能做个带翻页动画的阅读器吧!

    preview1 preview2 preview3

    项目地址:GitHub
    觉得好的话star一下

    文章顺序:

    • 翻页
    • 内容
    • 工具栏

    翻页

    主要是按照
    Android自定义View——从零开始实现书籍翻页效果
    的逻辑,自己手敲了一遍完成的翻页动画,并对代码进行了调整。
    期间也学习了
    各个击破搞明白PorterDuff.Mode
    一起看画布Android Canvas
    对代码理解和调整起到了很大帮助。

    这里就不赘述以上文章的内容,直接说明调整后的代码逻辑。

    自定义控件继承自View,通过重写

    • onMeasure 来获取控件的宽高,取得纸张各点的初始值
    • onDraw 用来绘制纸张、阴影、内容
    • onTouchEvent 获取用户的手势事件,重计算各点并绘制,达到翻页的动效
    • computeScroll 用到了Scroller,来执行手势事件后的翻页、恢复效果

    初始化

    因为视图是通过Canvas绘制出来的,因此控件初始化时要将

    • Point 书页运动的关键点,用于完成翻页动画
    • Paint 内容画笔
    • Path A、B、C区域的路径,用于翻页时路径的裁剪
    • Gradient 阴影

    初始化,并打开setClickable(true),用以接收手势事件

    测量

    按View的生命周期,到了onMeasure

    设置BookPageView的宽高后,便有了关键点的初始值。通过宽高值,初始化A、B两个不同区域的Bitmap。

    绘制

    具备了Point、Paint、Path、Gradient、Bitmap,便可以开始绘制Canvas。

    将准备好的纸图片,绘制到Canvas当全局背景,用以填充裁剪所漏出的区域。

    具体的绘制过程需要根据翻页的方向进行区分,因为翻页的方向不同,导致各关键点的计算公式、阴影位置不同。

    触点

    区域划分

    ACTION_DOWN时判断翻页的位置,预先加载前一页or后一页的内容到Bitmap上,并计算各点坐标。

    正常状况下滑动不予翻页,避免突兀到翻页效果。

    翻页结束,根据预设条件判断翻页还是恢复,并调用Scroller.startScroll。

    内容

    由于翻页相关的内容主体逻辑已经在引用中有了详细的解释,所以没必要用篇幅再去讲解一遍。

    但内容相关的代码会详细介绍,涉及到字体大小所影响的页面显示、TXT内容的读取策略等

    根据最少知识原则设计内部类ContentController,用以读取文件、缓存内容、获取当前内容。

    根据TXT小说的大体估计,平均一行约500汉字,共占1000字节约1K。

    每页约1~3行,由每行字数多少决定。

    缓存策略为缓存50页:当前页的前10页、包括当前页的后40页。

    获取指定页内容(待优化)

    从缓存中取,若指定页为阀值,则更新缓存。

    待优化点:

    • 未预先缓存数据,现在显示正常是因为onMeasure的多次执行,导致initBitmapA多次执行,从而代替了预先缓存。如果内容不变的话initBitmapA不应该多次执行。

    更新指定页前后的内容(待优化)

    根据当前页计算,需缓存的前后页码。

    待优化点:

    • 重复内容并没有重用,(现缓存1~50,需缓存37~87,则37~50内容重复)。但限于读取的方式,暂没想到好的解决办法,见下。

    获取指定范围的内容(重点)

    初始数组,获取输入流

    标记第一页,根据字体大小计算每页及每行可容纳的字数。

    标准IO操作,读取每行内容,计算当前行长度+当前页内容长度,是否超过当页容量,超过则放到下一页。当这页已满,stringBuffer.toString()放入result数组,页数加一。

    由于每次读取都是从第1页开始,若缓存30~80页,则先读取前30页的内容并抛弃,然后才存到数组缓存。

    所以要判断

    待优化点:

    • 现读取的是raw中的文件,可优化选择文件功能
    • 每次读文件都是从第一行开始读,读字节的话又会造成,前后页之间的文字乱码。(暂未想到解决办法)
    • 当一页的第一行只有1个或很少的字数并换行,且接下来的段落每行字数都很满,则会造成最后一行绘出屏幕

    工具栏

    一个完整的书页,需要有工具栏来设置字体、字号、背景色等多种功能。这里只提供了工具栏,至于具体的工具待填充。

    由于没有工具,所以


    这里完全可以如上所说代码布局,我省个事!!

    在onFinishInflate,获取对应控件。不必担心回调优先执行导致控件空指针,此处控件已初始化完成,并setText,在onMeasure和onLayout中也只会对控件进行拉伸显示

    对控件进行测量,切记注意EXACTLY、AT_MOST与实际xml中填写项的对应。

    这里布局子View,需要注意layout时,不要只在乎左上角的点,右下角同样重要,否则控件会被拉伸。

    动画效果采用了Animator,属性动画,通过改变自定义属性,不停的layout达到效果

    相关文章

      网友评论

      • EvanZch:厉害,支持PDF吗?
        s1991721:@Evan_zch 纯文本的PDF可以通过pdfbox 或其他库加载内容,但图片类型的我不敢保证显示正常:joy:
      • Jooyer:大佬,厉害,我也参考了那位大佬,但是效果不理想😀
        s1991721:@Jooyer 多看看讲解!把代码fork下来一步步删除代码跑,就会明白代码的用意

      本文标题:空手撸一个Android阅读器,无第三方支持

      本文链接:https://www.haomeiwen.com/subject/ioltaftx.html