[Android] TextView 分页功能的实现

为什么80%的码农都做不了架构师?>>>   hot3.png

分页功能是阅读器类软件的基本功能之一, 也是自己之前写阅读器时遇到的第一个问题. 尝试了不少办法才解决, 现在把其中最容易实现的一个方法记录下来, 也方便大家参考.

基本思路如下:

  1. 从文件中读取 8000 个字符至缓冲区
  2. 将表示位置的指针指向缓冲区开头
  3. 让 TextView 显示从指针所指位置开始的内容
  4. 获取 TextView 中的可见字数 n
  5. 将指针向后移动 n 位
  6. 向后翻页时执行 3 ~ 5 步

整体思路很简单, 其中唯一的难点就是第 4 步, 如何获取 TextView 中的可见字数.

我遇到这类问题一般就是两步走, 先文档, 后源码.

所以先去查 Android 文档, 看看 TextView 有没有什么可以利用的函数. 在其中找到一个函数:

getLineBounds(int line, Rect bounds) // 得到指定行的边界

似乎有点用. 只要从第一行开始一行一行往下看, 直到找到超出边界的那一行, 就能知道这个 TextView 能显示多少行了. 或者用 getHeight() / getLineHeight() 也能获取 TextView 的最大显示行数. 但由于并不知道每行的字数, 所以还是算不出来一页到底有多少字.

后来又尝试了许多其他方法, 也在提问区问过. 结果只得到了一个建议, 就是自己写个 View. 整个 View 都由自己实现的话, 的确能很方便地控制所有细节, 但随之而来的麻烦就是, 所有的细节都得自己实现. 比如我的断行, 和布局自适应这两点处理得就没原生的 TextView 那么好, 只能说勉强能用. 更别提超链接这类的东西了, 要想全部实现还真不是一时半会能搞定的.

既然查文档无果, 那就只能去看源码了. 不看不知道, 这不起眼的 Textview 源码居然有近 9000 行, 顿时有点犯晕. 不过我的目标只有一个, 搞清楚 TextView 是怎么排版的. 所以直接看 onDraw(Canvas canvas) 函数, 在其中找到这么一行:

layout.draw(canvas, highlight, mHighlightPaint, cursorOffsetVertical);

由此可以推断 TextView 排版及绘制文字靠的就是这个 layout, 所以立刻到文档中找 Layout, 这次终于在其中找到了几个有用的函数(就是那些 getLine*** 函数), 最有用的是这两个:

getLineForVertical(int vertical) // 根据纵坐标得到对应的行号

getLineEnd(int line) // 返回指定行中最后一个字在整个字符串中的位置

所以我们只要先计算出最下面一行是第几行, 然后再算出这行最后一个字是第几个字就行了.

先算行号:

public int getLineNum() {Layout layout = getLayout();int topOfLastLine = getHeight() - getPaddingTop() - getPaddingBottom() - getLineHeight();return layout.getLineForVertical(topOfLastLine);
}

再算字数:

public int getCharNum() {return getLayout().getLineEnd(getLineNum());
}

这样我们就能得到 TextView 在本页所显示的字数了.

public class ReadView extends TextView {// 构造函数略...@Overrideprotected void onLayout(boolean changed, int left, int top, int right, int bottom) {super.onLayout(changed, left, top, right, bottom);resize();}/*** 去除当前页无法显示的字* @return 去掉的字数*/public int resize() {CharSequence oldContent = getText();CharSequence newContent = oldContent.subSequence(0, getCharNum());setText(newContent);return oldContent.length() - newContent.length();}/*** 获取当前页总字数*/public int getCharNum() {return getLayout().getLineEnd(getLineNum());}/*** 获取当前页总行数*/public int getLineNum() {Layout layout = getLayout();int topOfLastLine = getHeight() - getPaddingTop() - getPaddingBottom() - getLineHeight();return layout.getLineForVertical(topOfLastLine);}
}

示例工程下载: http://pan.baidu.com/share/link?shareid=3043803389&uk=1563550261

转载于:https://my.oschina.net/gotax/blog/136860

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/293500.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

把男朋友变成儿子你只需要一秒

1 别人以为的我▼2 幸好有监控,差点就没法和老婆解释了!▼3 为了卖化妆品我已经不止一次假装我有一群舔狗了▼4 这么多年下来班主任的这些套路谁还不清楚呢?▼5 司机同志们注意啦要主动停车接受检查▼6 让男友变儿子你只需要一秒钟▼7 …

thinkphp与php共享session

在其他php页面添加如下代码即可 if (!session_id()) session_start(); 使用时 thinphp 使用 session(test,123); $user_info $_SESSION[test]; var_dump($test); //123 转载于:https://www.cnblogs.com/yun007/p/3806385.html

Android之使用HandlerThread 以及如何退出总结

1 、使用 HandlerThread handlerThread = new HandlerThread("handlerThread"); handlerThread.start(); //这里获取到HandlerThread的runloop MyHandler myHandler = new MyHandler(handlerThread.getLooper()); 2、介绍 和主线程已经没有关系了,所以不能跟新…

容器界的新“朋友”

微软中国MSDN 点击上方蓝字关注我们Ignite 2021 上,微软发布了Azure Container Apps,这是一种以无服务器应用程序为中心的托管服务,用户看不到或无需管理任何底层 VM、协调器或其他云基础架构。Azure Container Apps支持打包在容器中的任何应…

分析函数在数据分析中的应用

我们来看看下面的几个典型例子: ①查找上一年度各个销售区域排名前10的员工 ②按区域查找上一年度订单总额占区域订单总额20%以上的客户 ③查找上一年度销售最差的部门所在的区域 ④查找上一年度销售最好和最差的产品 我们看看上面的几个例子就可以感觉到这几个查询…

LateUpdate、Late、FixedUpdate的意义

1、MonoBehaviour.Update 更新 当MonoBehaviour启用时,其Update在每一帧被调用。 2、MonoBehaviour.FixedUpdate 固定更新 当MonoBehaviour启用时,其 FixedUpdate在每一帧被调用。 处理Rigidbody时,需要用FixedUpdate代替Update。例如:给刚体…

JSP中一个页面怎么分清是链接过来还是提交过来的?

处理代码&#xff1a;String action request.getParameter("action");if (action ! null && action.trim().equals("post")) {}form里面的代码&#xff1a;<form action"post.jsp" method"post"> …

史上最“可怕”的数学科普,能全都看懂的只有天才!

▲ 点击查看我们在生活中&#xff0c;或许最常听到的一句话就是&#xff1a;“数学是工具”。在《数学家的眼光》一书的开篇中&#xff0c;张景中院士却举了一个颠覆我们平常认知的例子&#xff1a;大数学家陈省身有一次在北京大学的讲座中语惊四座&#xff1a;“人们常说三角形…

ubuntu环境下如何解决svn提交出现can‘t check path ‘/home/...‘

在ubuntu环境下用svn提交代码出现这个错误 cant check path /home/... 因为我们提交有限制 我一开始是这样写的 svn commit -m $ noreview [问题单号]:1234 然后报错出现了这个bug 解决办法&#xff1a; svn commit -m $ noreview [问题单号]:1234 记住了 $ 中间不能…

received packet with own address as source address

故障现象&#xff1a;网卡做bond后&#xff0c;在messages中频繁出现received packet with own address as source address。问题分析&#xff1a;该问题由于网卡做bond后上层链路交换机没有做port channel而产生错误。比如网卡做bond mode 0&#xff0c;上层交换无任何配置&am…

.NET6之MiniAPI(五):选项

选项是配置一个升级版&#xff0c;一般情况下是把一个范围内的配置包装成类型&#xff0c;以供使用&#xff0c;比如下面的RedisSetting&#xff0c;是Redis的配置参数&#xff1a;{"Logging": {"LogLevel": {"Default": "Information"…

解决nginx不支持pathinfo Thinkphp命名空间问题

1.这是我Ubuntu14.4配置文件server { listen 9989 default_server; # SSL configuration # # listen 443 ssl default_server; # listen [::]:443 ssl default_server; # # Note: You should disable gzip for SSL traffic. # See: https://bugs.debia…

Oracle常用知识总结

1.曾经不小心把开发库的数据库表全部删除&#xff0c;当时吓的要死。结果找到下面的语句恢复到了1个小时之前的数据&#xff01;很简单。 注意使用管理员登录系统&#xff1a; select * from 表名 as of timestamp sysdate-1/12 //查询两个小时前的某表数据&#xff01;既然两…

Android之项目中调用已有.so库

注意该.so库指的是android平台的&#xff0c;非一般linux、unix平台&#xff1b; 1、现有库libcom_ycan_testLib.so 2、新建android项目TestLib2 3、添加新类&#xff1a; 类名&#xff1a;testLib 包路径&#xff1a;参考现有库名&#xff0c;应为com.ycan 4、在新类中声明库的…

数组面试题--数组求和

题目描述&#xff1a;给定一个数组&#xff0c;实现函数用一行代码返回这个数组的和 思路&#xff1a;递归即可 1 #include <iostream>2 #include <queue>3 #include <climits>4 #include <algorithm>5 #include <memory.h>6 #include <stdio…

iNeuOS工业互联网操作系统,矿山动态产量计量系统和铁路车辆识别系统应用场景案例...

目 录1. 概述... 22. 平台演示... 23. 矿山动态产量计量系统... 24. 铁路车辆识别系统... 41. 概述iNeuOS工业互联网操作系统增加矿山动态产量计量和铁路车辆识别系统&#xff0c;提高矿山动态产量计量精度和完全避免产量核实误差的情况&#xff1…

85元一个万能工具箱,配齐24种螺丝刀+扳手,媲美德国工艺,家庭必备

▲ 点击查看对当代的男生来说&#xff0c;有什么技能是必须掌握的&#xff1f;自然是修理各种各样的东西啦~除了修电脑&#xff0c;还要修各种电器啊、家具啊之类的&#xff0c;讲真&#xff0c;会修理的男人都很帅&#xff01;实用性能也满分&#xff0c;相当于女孩子会做饭一…

poj1505

题意&#xff1a;给出一个数列有n个数&#xff0c;要求用分割分把这个数列分成m段&#xff0c;不能改变原数列的顺序。每段至少一个数。求使得加和最大的那段的加和最小的划分方案。如果有多组解的话先要保证第一段和尽量小&#xff0c;若仍有多组解&#xff0c;要先保证第二段…

mysql出现连接错误不识别 utf8mb4

2019独角兽企业重金招聘Python工程师标准>>> 出现这样的错误&#xff0c;指的是不识别该字符集。 可能是 数据库 里面配置 或者是 连接属性 配置了该字符集那么修改回来即可。 还有一种情况就是 &#xff0c;java-connert-sql连接包&#xff0c;版本太低了。比如 低…

Android之录音--AudioRecord、MediaRecorder

Android提供了两个API用于实现录音功能&#xff1a;android.media.AudioRecord、android.media.MediaRecorder。 网上有很多谈论这两个类的资料。现在大致总结下&#xff1a; 1、AudioRecord 主要是实现边录边播&#xff08;AudioRecordAudioTrack&#xff09;以及对音频的实时…