“ 人之所以能,是相信能。”
github地址:https://github.com/shuaijia/NoteText
01
—
前言
最近公司有意需求,就是类似于电子书,选择一段文字然后做笔记,需要给做过的文字加下划线,下划线最后加一图标按钮,点击弹框显示笔记内容。
立马会想到使用TextView的fromHtml方法,给添加笔记的文本手动加标签,或者使用SpanString类的相关方法设置标签。
但是!
经过反复测试,无论使用何种下划线标签或者SpanString设置下划线,画出的下划线颜色始终和文本内容颜色一样,还不能随便定义颜色。更何况:我们需要在下划线最后加图标,并且能够点击。看来这种方法不可行…
于是,便开始了我的自定义之路~~~~
先看效果图:
这是纯文本的TextView
这是富文本的TextView
02
—
分析
要实现以上需求,应该从这几个方面入手:
文本展示,普通文本调用TextView的setText方法既可,如果是富文本,就使用TextView的fromHtml方法,至于图片如何展示,我在上一篇文章用TextView实现富文本展示,点击断句和语音播报介绍过了,有兴趣的可以跳转阅读,核心是拦截到图片url然后自己实现加载图片。
给TextView设置要划线的起始位置和结束位置,需要计算出在哪些行进行绘制,每行又是从哪里开始,到哪里结束,注意第一行和最后一行。
然后就是在onDraw方法中对计算出的行进行逐行绘制,在最后一行的结束位置绘制笔记图标(小圆圈)。
在TextView的onTouchEvent判断按下位置是否是笔记图标(小圆圈)的附近,是的话则弹框(PopupWindow)显示。
03
—
文本显示
这里就不再重复累赘了,文本展示很简单:
调用setText或fromHtml方法既可。
04
—
颜色等属性设置
我们需要定义画笔、画笔颜色、线条粗细;开始位置的结束位置的索引。
还有就是下划线的位置,因为我们是按行来画,每画完一行就会重新计算,尤其是横向的结束位置,所以我将x的结束位置定义出来,每次都更新。
最后要将计算出的小图标的x和y值保留,在onTouchEvent中会用到。
并初始化:
05
—
计算划线位置
我们先定义一个实体类,这个类中存放每行的索引,和对应每行上的一个开始位置索引,结束位置索引。
定义两个集合,分别存放所有行的信息和需要绘制的行的信息。
接下来开始计算:
思路是这样的:
06
—
绘制下划线
核心使用的是canvas的drwaLine方法进行绘制。
循环所有要绘制的集合,得到这一行的外包矩形,根据当前行的开始和结束位置,算出横向x的开始和结束位置;baseline是字符底部y的值,这样就可以绘制划线了!
07
—
绘制笔记图标
如果是最后一行的,在本行的结束位置开始绘制笔记图标。
使用canvas.drawCircle绘制圆圈,而圆的圆形坐标可以下划线最后的位置进行绘制。
再用另一条画笔绘制三个白点,这个白点可以使用canvas.drawPoints绘制,传入一个float类型数组,下标是奇数,表示点的x值,下表为偶数,表示点的y值,也就是说float数组的个数必须是偶数个,或者说是点数的两倍。
08
—
图标点击
在上一步绘制小图标时,就将图标的x和y值保存,在onTouchEvent中,判断按下的位置是否在小图标位置的“附近”,是的话就弹框显示笔记内容。
这里的弹框用的是我之前封装的JsPopupWindow,有兴趣的话可以点击阅读https://github.com/shuaijia/JsPopupWindow。
这里需要注意,如果TextView外层被ScrollView包裹,在弹框是就需要纵轴方向上减去ScrollView的偏移量。也就是TextView需要知道ScrollView的纵向偏移量,这里我设置了方法,将ScrollView的偏移量传入。
这样就实现了我们如上图展示的,给TextView绘制下划线和图标点击,弹框的效果。