IT技術互動交流平台

快3注册官网

來(lai)源︰IT165收集(ji)  發布日期︰2020-02-22 04:38:49

快3注册官网

在應用程序開發過程經常需要對文本進行xie) 恚 熱ru)說對一(yi)段描(miao)述文字zhi)de)其中一(yi)段加入點擊事件,或者(zhe)對yun)瀋柚貌bu)一(yi)樣的(de)前景(jing)色,有(you)什(shi)麼方(fang)法可以實現要求的(de)功能吶?

快3注册官网

比如(ru)我們需要實現如(ru)下圖所示的(de)功能,將(jiang)文本︰#重磅(bang)消息#近日谷歌放出Android N的(de)第二個開發者(zhe)預(yu)覽版(Developer Preview) 處理成(cheng)第二種或者(zhe)第三(san)種zhi)de)形式。

這里寫(xie)圖片(pian)描(miao)述

快3注册官网

根據上圖,我們可以采用如(ru)下的(de)方(fang)法來(lai)實現上訴要求的(de)效(xiao)果。

方(fang)案1

比如(ru)顯(xian)示效(xiao)果二你(ni)可以能會說,我們可以采用三(san)個TextView來(lai)實現,第一(yi)個TextView設置不(bu)一(yi)樣的(de)顏(yan)色,第二個正(zheng)常顯(xian)示內容,第三(san)個處理點擊事件。該方(fang)式對圖二可能是能夠實現zhi)de),但(dan)是如(ru)果第二行里面(mian)就(jiu)有(you)部分內容需要進行點擊處理,就(jiu)比較難以實現了。

對于(yu)圖三(san)的(de)效(xiao)果上述的(de)方(fang)式就(jiu)很難實現了。必須(xu)要對TextView的(de)內容進行xie)  耍。/p>

方(fang)案2

如(ru)果文案的(de)處理只是簡單的(de)對yun)耄 yan)色,大小(xiao)的(de)變換,我們還(huai)可以采用自定義view來(lai)實現,在前面(mian)的(de)文章中我們就(jiu)采用了自定義view來(lai)顯(xian)示了一(yi)個文字zhi)de)排(pai)版效(xiao)果,具體實現可以查看Android文本排(pai)版實現;

方(fang)案3

除了上面(mian)的(de)方(fang)案,我們還(huai)可以采用另(ling)外(wai)一(yi)個種方(fang)式來(lai)實現,采用html來(lai)顯(xian)示,可以將(jiang)要顯(xian)示的(de)內容轉換成(cheng)html的(de)格式,用TextView來(lai)進行加載。說了這麼多(duo),我們來(lai)看看代碼(ma)吧!

private void setText() { String originText = '#重磅(bang)消息#近日谷歌放出Android N的(de)第二個開發者(zhe)預(yu)覽版(Developer Preview)'; String effect1 = '<font color='#FF0000'>#重磅(bang)消息#</font> <br> 近日谷歌放出Android ' +  'N的(de)第二個開發者(zhe)預(yu)覽版<a href='http://developer.android.com/index.html'>(Developer Preview)</a>'; String effect2 = '<font color='#303F9F'>#重磅(bang)消息#</font> 近日谷歌放出Android ' +  'N的(de)第二個開發者(zhe)預(yu)覽版<a href='http://developer.android.com/index.html'>(Developer Preview)</a>'; StringBuilder sb = new StringBuilder(originText); sb.append('<br><br><br><br>'); sb.append(effect1); sb.append('<br><br><br><br>'); sb.append(effect2); textView.setText(Html.fromHtml(sb.toString())); textView.setMovementMethod(LinkMovementMethod.getInstance());}

寫(xie)到這,突然發現要跑題,僅僅是Html的(de)實現就(jiu)可以分析出很多(duo)的(de)知(zhi)識點,不(bu)huai)飫 huai)是先契合(he)主題,先這里挖一(yi)個坑,後續對html進行分析,查看鏈接,現在還(huai)未實現

方(fang)案4

終于(yu)回到我們的(de)主題了,這里我們采用SpannableString來(lai)實現上述的(de)效(xiao)果。代碼(ma)如(ru)下︰

private void setSpan() { String originText = '#重磅(bang)消息#近日谷歌放出Android N的(de)第二個開發者(zhe)預(yu)覽版(Developer Preview)'; SpannableStringBuilder sb = new SpannableStringBuilder(originText); sb.append('').append('').append(''); getEffect1Span(sb); sb.append('').append('').append(''); getEffect2Span(sb); textView.setText(sb); textView.setMovementMethod(LinkMovementMethod.getInstance());}private void getEffect1Span(SpannableStringBuilder sb) { String source1 = '#重磅(bang)消息#'; SpannableString span = new SpannableString(source1); span.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.colorAccent)), 0, source1.length(),  Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); sb.append(span); sb.append(''); String source2 = '近日谷歌放出Android N的(de)第二個開發者(zhe)預(yu)覽版'; sb.append(source2); final String source3 = '(Developer Preview)'; SpannableString clickSpan = new SpannableString(source3); clickSpan.setSpan(new ClickableSpan() { @Override public void onClick(View widget) {  ToastUtil.showLong(source3); } }, 0, source3.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); sb.append(clickSpan);}private void getEffect2Span(SpannableStringBuilder sb) { String source1 = '#重磅(bang)消息#近日谷歌放出Android N的(de)第二個開發者(zhe)預(yu)覽版'; SpannableString span = new SpannableString(source1); span.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.colorPrimaryDark)), 0, 6, Spanned  .SPAN_EXCLUSIVE_EXCLUSIVE); sb.append(span); final String source2 = '(Developer Preview)'; SpannableString clickSpan = new SpannableString(source2); clickSpan.setSpan(new ClickableSpan() { @Override public void onClick(View widget) {  ToastUtil.showLong(source2); } }, 0, source2.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); sb.append(clickSpan);}

上述代碼(ma)采用了硬(ying)編碼(ma)方(fang)式實現,正(zheng)常實現,需要根據需求進行設置。記得要添(tian)加textView.setMovementMethod(LinkMovementMethod.getInstance());來(lai)接受點擊事件。

快3注册官网

SpannableString繼承了SpannableStringInternal,同時(shi)實現了CharSequence, GetChars, Spannable三(san)個接口,正(zheng)常處理文本的(de)函數為setSpan函數︰

public void setSpan(Object what, int start, int end, int flags) { super.setSpan(what, start, end, flags);}

該函數有(you)四個參數,第一(yi)個為一(yi)個span類型,第二個參數為開始位置,第三(san)個位置為span的(de)結束位置,最(zui)後一(yi)個為flag參數。
what可以設置如(ru)下類型︰

1, AbsoluteSizeSpan 設置文字字體的(de)絕(jue)對大小(xiao), 有(you)兩(liang)個參數,第一(yi)個是字體大小(xiao),第二個是單位是否是dip

public AbsoluteSizeSpan(int size, boolean dip) { mSize = size; mDip = dip; }

2,AlignmentSpan 主要設置文本的(de)對yun)敕fang)式,有(you)三(san)種方(fang)式正(zheng)常,居you)校 嚳fan)的(de)方(fang)式對yun)耄  鮮迪治tandard

 public Standard(Layout.Alignment align) { mAlignment = align; }

3,BackgroundColorSpan 設置文字zhi)de)背景(jing)色

private void setfCS(){ String source1 = '#重磅(bang)消息#'; SpannableString span = new SpannableString(source1); span.setSpan(new BackgroundColorSpan(getResources().getColor(R.color.colorAccent)), 0, source1.length(),Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); textView.setText(span);}

4,BulletSpan 給(gei)文本的(de)開始處加上項目符號。比如(ru)前面(mian)加一(yi)個 .

private void setBSpan() { final String source3 = '近日谷歌放出Android N的(de)第二個開發者(zhe)預(yu)覽版'; SpannableString bSpan = new SpannableString(source3); bSpan.setSpan(new BulletSpan(), 0, source3.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); textView.setText(bSpan);}

5, ClickableSpan 設置文本的(de)點擊事件,要實現onClick函數,可以復寫(xie)updateDrawState,設置下劃線,或者(zhe)取消下劃線,還(huai)可以設置下劃線顏(yan)色

private void setCS(){ final String source2 = '(Developer Preview)'; SpannableString clickSpan = new SpannableString(source2); clickSpan.setSpan(new ClickableSpan() { @Override public void onClick(View widget) {  ToastUtil.showLong(source2); } }, 0, source2.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); textView.setText(clickSpan);}

6,DrawableMarginSpan 可以設置一(yi)個圖標,並且可以設置與文字zhi)de)寬度

private void setDMSpan() { final String source3 = '(Developer Preview)'; SpannableString dmSpan = new SpannableString(source3); dmSpan.setSpan(new DrawableMarginSpan(getResources().getDrawable(R.mipmap.ic_launcher), 30), 0, source3  .length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); textView.setText(dmSpan);}

7,DynamicDrawableSpan 設置某段文字被圖標替換,需要返(fan)回一(yi)個drawable

8,EasyEditSpan 當(dang)文本改變或者(zhe)刪除時(shi)調用, 例如(ru)入下長按可以很容易刪除一(yi)行

private void setEdit() { editText.setInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS); editText.setSingleLine(false); editText.setText('近日谷歌放出Android N的(de)第二個開發者(zhe)預(yu)覽版'); editText.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) {  final Layout layout = editText.getLayout();  final int line = layout.getLineForOffset(editText.getSelectionStart());  final int start = layout.getLineStart(line);  final int end = layout.getLineEnd(line);  editText.getEditableText().setSpan(new EasyEditSpan(), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);  return true; } });}

9,ForegroundColorSpan 設置文字前景(jing)色

private void setfCS(){ String source1 = '#重磅(bang)消息#'; SpannableString span = new SpannableString(source1); span.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.colorAccent)), 0, source1.length(),Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); textView.setText(span);}

寫(xie)到這里我停下來(lai)了。天(tian)啦嚕(lu),30多(duo)個span,可以去系統(tong)代碼(ma)package android.text.style包(bao)下查看,這麼多(duo),整個人都不(bu)好(hao)了。

這里寫(xie)圖片(pian)描(miao)述
因此(ci)先就(jiu)針(zhen)對上面(mian)的(de)做了部分樣例,之(zhi)後會專門實現一(yi)下每個span的(de)效(xiao)果。仔細(xi)理解一(yi)個就(jiu)行,其他的(de)都是類似的(de),我們繼續看看後面(mian)的(de)參數。

第二參數start和第三(san)個參數end,表示當(dang)時(shi)設置的(de)span作用效(xiao)果的(de)範圍,start表示開始位置,end表示結束位置,第四個參數是一(yi)個flag標簽。這里主要設置以下的(de)值(zhi)︰

/** * Non-0-length spans of type SPAN_INCLUSIVE_EXCLUSIVE expand * to include text inserted at their starting point but not at their * ending point. When 0-length, they behave like marks. */public static final int SPAN_INCLUSIVE_EXCLUSIVE = SPAN_MARK_MARK;/** * Spans of type SPAN_INCLUSIVE_INCLUSIVE expand * to include text inserted at either their starting or ending point. */public static final int SPAN_INCLUSIVE_INCLUSIVE = SPAN_MARK_POINT;/** * Spans of type SPAN_EXCLUSIVE_EXCLUSIVE do not expand * to include text inserted at either their starting or ending point. * They can never have a length of 0 and are automatically removed * from the buffer if all the text they cover is removed. */public static final int SPAN_EXCLUSIVE_EXCLUSIVE = SPAN_POINT_MARK;/** * Non-0-length spans of type SPAN_EXCLUSIVE_INCLUSIVE expand * to include text inserted at their ending point but not at their * starting point. When 0-length, they behave like points. */public static final int SPAN_EXCLUSIVE_INCLUSIVE = SPAN_POINT_POINT;

常用的(de)就(jiu)是上述的(de)四個值(zhi),這里我們來(lai)分別解釋以下:
1. SPAN_INCLUSIVE_EXCLUSIVE表示左閉右開區間 “[ )”
2. SPAN_INCLUSIVE_INCLUSIVE表示左右都是閉區間 ‘( )’
3. SPAN_EXCLUSIVE_EXCLUSIVE表示左右都是閉區間 ‘[ ]’
4. SPAN_EXCLUSIVE_INCLUSIVE表示左右都是閉區間 ‘( ]’

我們繼續來(lai)看代碼(ma),SpannableString的(de)setSpan又(you)繼續調用了SpannableStringInternal的(de)setSpan函數。

/* package */ void setSpan(Object what, int start, int end, int flags) { int nstart = start; int nend = end; checkRange('setSpan', start, end); if ((flags & Spannable.SPAN_PARAGRAPH) == Spannable.SPAN_PARAGRAPH) { if (start != 0 && start != length()) {  char c = charAt(start - 1);  if (c != '')  throw new RuntimeException(   'PARAGRAPH span must start at paragraph boundary' +   ' (' + start + ' follows ' + c + ')'); } if (end != 0 && end != length()) {  char c = charAt(end - 1);  if (c != '')  throw new RuntimeException(   'PARAGRAPH span must end at paragraph boundary' +   ' (' + end + ' follows ' + c + ')'); } } int count = mSpanCount; Object[] spans = mSpans; int[] data = mSpanData; for (int i = 0; i < count; i++) { if (spans[i] == what) {  int ostart = data[i * COLUMNS + START];  int oend = data[i * COLUMNS + END];  data[i * COLUMNS + START] = start;  data[i * COLUMNS + END] = end;  data[i * COLUMNS + FLAGS] = flags;  sendSpanChanged(what, ostart, oend, nstart, nend);  return; } } if (mSpanCount + 1 >= mSpans.length) { Object[] newtags = ArrayUtils.newUnpaddedObjectArray(  GrowingArrayUtils.growSize(mSpanCount)); int[] newdata = new int[newtags.length * 3]; System.arraycopy(mSpans, 0, newtags, 0, mSpanCount); System.arraycopy(mSpanData, 0, newdata, 0, mSpanCount * 3); mSpans = newtags; mSpanData = newdata; } mSpans[mSpanCount] = what; mSpanData[mSpanCount * COLUMNS + START] = start; mSpanData[mSpanCount * COLUMNS + END] = end; mSpanData[mSpanCount * COLUMNS + FLAGS] = flags; mSpanCount++; if (this instanceof Spannable) sendSpanAdded(what, nstart, nend);}/* package */ void removeSpan(Object what) { int count = mSpanCount; Object[] spans = mSpans; int[] data = mSpanData; for (int i = count - 1; i >= 0; i--) { if (spans[i] == what) {  int ostart = data[i * COLUMNS + START];  int oend = data[i * COLUMNS + END];  int c = count - (i + 1);  System.arraycopy(spans, i + 1, spans, i, c);  System.arraycopy(data, (i + 1) * COLUMNS,    data, i * COLUMNS, c * COLUMNS);  mSpanCount--;  sendSpanRemoved(what, ostart, oend);  return; } }}

首先調用了checkRange,判斷(duan)了位置的(de)合(he)法性(xing),如(ru)果start小(xiao)于(yu)end,或者(zhe)位置下標越界都會拋(pao)出IndexOutOfBoundsException異常。

之(zhi)後判斷(duan)了(flags & Spannable.SPAN_PARAGRAPH) == Spannable.SPAN_PARAGRAPH是否相等,這里如(ru)果設置的(de)是上述四個值(zhi),這里是不(bu)等的(de),所以不(bu)會進入該判斷(duan)。

設置了count,第一(yi)次count為0,設置了spans數組與data,第一(yi)次設置的(de)值(zhi)是在構造函數中初始化(hua)的(de)值(zhi)。

因為count為0,因此(ci)for循環也不(bu)會進入

之(zhi)後判斷(duan)了mSpanCount + 1 >= mSpans.length,這里前面(mian)為1,後面(mian)為0,因此(ci)會進入if判斷(duan),首先申請(qing)了一(yi)個3個長度的(de)newtags數組,一(yi)個9個長度的(de)int數組, 之(zhi)後進行了兩(liang)次數據拷貝,將(jiang)已yan)you)的(de)span拷貝到新(xin)申請(qing)的(de)數組中,將(jiang)其他參數拷貝到新(xin)的(de)int數組中xiao)/p>

之(zhi)後將(jiang)改成(cheng)設置的(de)span設置到mSpans數組中,將(jiang)其他的(de)參數設置到mSpanData,三(san)個參數是連續設置的(de)。

最(zui)後調用了sendSpanAdded,代碼(ma)如(ru)下︰

private void sendSpanAdded(Object what, int start, int end) { SpanWatcher[] recip = getSpans(start, end, SpanWatcher.class); int n = recip.length; for (int i = 0; i < n; i++) { recip[i].onSpanAdded((Spannable) this, what, start, end); }}

這個調用了getSpans,返(fan)回了一(yi)個SpanWatcher數組,SpanWatcher是一(yi)個接口,MultiTapKeyListener, TextKeyListener實現了該類,因此(ci)當(dang)調用了TextKeyListener或者(zhe)MultiTapKeyListener會對相應的(de)span進行xie) 懟/p>

快3注册官网

這里只是大致的(de)解析了SpannableString,他還(huai)需要結合(he)TextView進行分析,看看在界面(mian)繪制的(de)時(shi)候是怎樣解析顯(xian)示的(de)。後續有(you)時(shi)間會陸(lu)續進行解析的(de)。

最(zui)後附(fu)一(yi)個鏈接,在我解析span的(de)時(shi)候,解析了幾個感覺(jue)太多(duo),就(jiu)搜索一(yi)下是否已經有(you)人解析過,因此(ci)這個這里加上跳轉鏈接,如(ru)果有(you)版權或者(zhe)不(bu)讓導(dao)航,請(qing)告知(zhi),我好(hao)刪除。傳送(song)門

快3注册官网

    • 快3注册官网

    About IT165 - 廣告服務(wu) - 隱(yin)私聲明 - 版權申明 - 中国体彩网官网免(mian)責(ze)條款 - 彩乐乐网官网網(wang)站地圖 - 網(wang)友投稿(gao) - 内蒙快3官网聯系方(fang)式
    本站內容來(lai)自于(yu)互聯網(wang),僅供用于(yu)網(wang)絡技術學習,學習中請(qing)遵循相關法律法規
    快3注册官网 | 下一页