Android开发之TextView分页功能的实现
2014-07-13 00:36
561 查看
分页功能是阅读器类软件的基本功能之一, 也是自己之前写阅读器时遇到的第一个问题. 尝试了不少办法才解决, 现在把其中最容易实现的一个方法记录下来, 也方便大家参考.
基本思路如下:
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 {
// 构造函数略...
@Override
protected 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);
}
}
基本思路如下:
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 {
// 构造函数略...
@Override
protected 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);
}
}
相关文章推荐
- Android开发:Android提供的CountDownTimer结合TextView实现倒计时功能
- Android开发TextView实现长按复制文本功能的方法
- [Android] TextView 分页功能的实现
- android Textview 实现展开收缩功能(字符宽度)(StaticLayout)
- android 倒计时、有清除功能编辑框、popupwindow、跑马灯效果实现(基于TextView)
- Android腾讯微博客户端开发5:利用FootView实现ListView滑动动态加载实现分页
- Android腾讯微博客户端开发5:利用FootView实现ListView滑动动态加载实现分页
- 【Android 开发】:UI控件之 ImageView 实现适屏和裁剪图片的功能
- Android开发之TextView实现跑马灯效果
- android中textview竖排显示,只能说功能实现了
- Android开发中TextView实现单行显示多余字用...表示
- Android开发:TextView实现跑马灯效果
- Android开发 TextView文字复制功能(类似EditText)
- Android腾讯微博客户端开发五:利用FootView实现ListView滑动动态加载实现分页
- Android控件使用—AutoCompleteTextView自动补全实现搜索功能
- Android开发UI之textview实现高亮显示并点击跳转
- Android开发————Android用AutoCompleteTextView实现搜索历史记录提示
- 【Android 开发】:UI控件之 ImageView 实现图片旋转和缩放功能
- android Textview 实现展开收缩功能+部分文字点击 (SpannableString)
- Android腾讯微博客户端开发5:利用FootView实现ListView滑动动态加载实现分页