原生高亮弊端
安卓原生textview控件自帶高亮功能稚机,只需在xml或者代碼中設(shè)置 android:textIsSelectable="true"即可蜡秽。但自帶的文本高亮功能有一些弊端:1:自由選擇的時(shí)候代赁,彈出的框可定制性差踊兜,在android6.0之前竿滨,大多數(shù)手機(jī)是不支持修改高亮框的,6.0后才允許修改捏境,但具體能修改成什么樣也不太確定于游。2:原生自帶的高亮功能是包括行高的效果圖
系統(tǒng)自帶的高亮?xí)r選中區(qū)域是包含行高的垫言,當(dāng)行高很大的時(shí)候,會很丑鸠澈。除此之外截驮,左右游標(biāo)的高度當(dāng)有富文本的時(shí)候,游標(biāo)的高還是固定的葵袭,也不是很美觀。ok坡锡,基于這兩點(diǎn)鹉勒,開啟我們自定制之旅。
認(rèn)識TextView
在開始高亮功能開發(fā)之前禽额,讓我們重新認(rèn)識一下textview。
有圖中可以看到行高部分是textview的leading值实辑,但是在textview中是獲取不到leading值的藻丢,各種log,一直是0残黑,即便設(shè)置了行高,也是0萍摊。所以把焦點(diǎn)放在了baseline和descent這兩個(gè)屬性上如叼。(此外這里有個(gè)需要注意點(diǎn),雖然沒有用到bottom值踊沸,但是textview在6.0之后社证,textview的最后一行的bottom的值是不包含行高的,跟之前的textviewbottom值有所差別追葡。)
高亮
安卓原生自帶的高亮是用textview眾多span中的BackgroundColorSpan實(shí)現(xiàn)的,但就是這個(gè)span是包含行高的匀钧,所以高亮的時(shí)候會一片區(qū)域全部選中谬返。經(jīng)過多次調(diào)研和可重寫性,最后選用LineBackgroundSpan來實(shí)現(xiàn)不帶行高的高亮遣铝。
首先寫一個(gè)CustomUnderlineSpan 實(shí)現(xiàn) LineBackgroundSpan類酿炸,實(shí)現(xiàn)drawBackground()方法,如圖:
LineBackgroundSpan是一個(gè)畫下劃線的樣式填硕,有第一部分我們可知baseline對我們來說非常重要,如果想排除行高频鉴,我們想畫的bottom值必須是baseline+descent 恋拍,在此回調(diào)方法中,我們可以拿到每一行的首字符下標(biāo)和每一行末尾的下標(biāo)周荐,還有這一行的baseline,top概作,paint等值。而重要的是descent我們可以用p.descent()獲得骤素。廢話少說愚屁,上代碼。
用原生的BackgroundSpan替換為自定義的CustomUnderLineSpan后就可以實(shí)現(xiàn)不帶行高的高亮文本功能了丘跌。
富文本高亮
由于Android有很多富文本渲染控件,所以自己可以根據(jù)自己的情況去實(shí)現(xiàn)高亮功能闭树。在此只介紹自己渲染富文本后如何實(shí)現(xiàn)高亮。
1:根據(jù)想高亮區(qū)間[start,end],計(jì)算出start對應(yīng)字符的左下標(biāo)點(diǎn)榆纽,end同理捏肢。
2:計(jì)算方法,逐個(gè)字符遍歷鸵赫,看是否存在圖片,如果存在圖片狼忱,則寬由字符的寬變?yōu)閳D片的寬
3:如果一行中含有圖片一睁,則高度也會隨之變化。
貼代碼:
左右游標(biāo)處理
1:原生的文本長按后窘俺,左右出現(xiàn)游標(biāo)复凳,拖拽游標(biāo)可改變高亮區(qū)域灶泵。原生的textview的實(shí)現(xiàn)方式是赦邻,左右游標(biāo)是PopupWindow,然后根據(jù)字符的index惶洲,計(jì)算出在屏幕中的位置劲妙,然后彈出pop儒喊,焦點(diǎn)也是放在游標(biāo)本身的。
2:我實(shí)現(xiàn)的方式是侨颈,在高亮文本的同時(shí)芯义,用代碼畫出左右游標(biāo),這樣左右游標(biāo)的高可以動態(tài)跟著富文本的高來變化扛拨,其次,左右游標(biāo)的焦點(diǎn)區(qū)域可以人為設(shè)置大小求泰。
原生的方式我也重寫了一下计盒,如果有疑問的小伙伴或者想交流的可以給我發(fā)信息。在此介紹第二種小清新的方式北启。
直接貼代碼
用代碼畫左右游標(biāo)
講述到此懈涛,主要的不帶行高的高亮功能基本算是實(shí)現(xiàn)了。
在此稍微提幾句計(jì)算下標(biāo)和焦點(diǎn)沖突的問題泣港。
計(jì)算下標(biāo)主要用到的代碼行:
int topVisibleLine = mLayout.getLineForVertical(y);
int offset = mLayout.getOffsetForHorizontal(topVisibleLine,x);具體使用到的方法,大家可以隨意Google
焦點(diǎn)沖突: TextView本身的長按事件呛每,點(diǎn)擊事件坡氯,和觸摸事件之間的沖突想必大家都很清楚了,這個(gè)我是沒有用長按和點(diǎn)擊事件箫柳,直接用觸摸事件自己判斷的長按事件和點(diǎn)擊事件,其中長按事件判斷時(shí)間是500ms库糠,點(diǎn)擊事件偏移量是50.
如有不嚴(yán)謹(jǐn)?shù)牡胤綒g迎更正
如有其它更好的方法涮毫,歡迎交流