[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 …

容器界的新“朋友”

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

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

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

.NET6之MiniAPI(五):选项

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

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

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

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

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

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

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

poj1505

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

mysql出现连接错误不识别 utf8mb4

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

一行代码完成定时任务调度,基于Quartz的UI可视化操作组件 GZY.Quartz.MUI

前言之前发布过第一个版本,有兴趣的可以去看看: NET Core 基于Quartz的UI可视化操作组件 GZY.Quartz.MUI 简介GitHub开源地址:l2999019/GZY.Quartz.MUI: 基于Quartz的轻量级,注入化的UI组件 总而言之,这个组件主要想做的就是:像swaggerUI一样,项目入侵量小,仅需要在Startup中注…

越绿自己,就会越强?

1 我们要求不高的(素材来源网络,侵删)▼2 小区的猫竟然通过监控抓老鼠(素材来源网络,侵删)▼3 不同职业的相亲对象(素材来源网络,侵删)▼4 别人家的年终奖&#xff0c…

Lync Server 2010迁移至Lync Server 2013部署系列 Part18:开启Lync 2013 Mobility

当我们将内部Lync 功能开通后,我们除了需要发布边缘开启外部登录功能外,我们还需要向用户提供Lync 手机登录功能,那么在今天的博文中我们就介绍一下关于如何开启Lync Mobility功能,就Lync 2013来讲,我个人认为开启Mobi…

使用springfox 集成swagger 与spring mvc

2019独角兽企业重金招聘Python工程师标准>>> 创建一个maven 模块 将springfox相关的配置都配置在一个单独的api模块中&#xff0c;可以把这个模块当成web应用跑起来。 <pluginRepositories> <pluginRepository> <id>jcenter-snapshots</id>…

技术分享 | CodeReview主要Review什么?

源宝导读&#xff1a;Code Review, 意即代码审查,是指一种有意识和系统的召集其他程序员来检查彼此的代码是否有错误的地方. 在敏捷团队中推行CodeReview, 可以帮助团队快速成长.本文将分享在"天际-建模平台"如何推行&实践CodeReview。一、为什么要 Code Review?…

你尿尿的时长是不是21秒?2次登上Nature封面的他,靠研究拉尿获得“诺贝尔奖”.........

全世界只有3.14 % 的人关注了爆炸吧知识男人的快乐就是这么朴实无华为什么蚊子不会被雨滴砸死&#xff1f;这个发在知乎上会被质疑患有十年脑血栓的问题&#xff0c;获得了2015年的中国搞笑诺贝尔奖——菠萝科学奖。获奖者结束获奖感言的方式也很搞笑&#xff1a;这个直接在“诺…

php curl用法

2019独角兽企业重金招聘Python工程师标准>>> curl 是使用URL语法的传送文件工具&#xff0c;支持FTP、FTPS、HTTP HTPPS SCP SFTP TFTP TELNET DICT FILE和LDAP。curl 支持SSL证书、HTTP POST、HTTP PUT 、FTP 上传&#xff0c;kerberos、基于HTT格式的上传、代理、…

Zabbix RCE with API JSON-RPC

测试脚本: #!/usr/bin/env python # -*- coding: utf-8 -*- # Software Link: http://www.zabbix.com/download.php # Version: 2.2 - 3.0.3import requests import json import sysdef verify(url,hostid):url url /api_jsonrpc.php ### Dont editlogin Admin ##…

探索 dotnet core 为何在 Windows7 系统需要补丁的原因

在一些 Windows 7 系统上&#xff0c;根据 dotnet 官方文档&#xff0c;需要安装上 KB2533623 补丁&#xff0c;才能运行 dotnet core 或 .NET 5 等应用。尽管非所有的设备都需要安装此&#xff0c;但这也让应用的分发不便&#xff0c;安装包上都需要带上补丁给用户安装。此补丁…

如何在单个测试中同时执行多个断言

前言虽然&#xff0c;推荐做法是每次测试只断言一件事&#xff0c;但是&#xff0c;在实际工作中&#xff0c;我们可能需要对同一个对象同时执行多个断言。例如&#xff0c;微软官方示例项目eShopOnContainers有一个测试用例的实现代码如下&#xff1a;[Fact] public async Tas…