[實戰筆記]Android文本編輯的一些實用技巧

有一段時間忙碌了,今天就好好總結記錄一下這陣子學到的一些小技巧好了。這一篇先記錄一下關於文本編輯的小事兒,Here we go!

************************************************

一、插入符號

現在做的項目由於是多語言的,加上剛好遇到需要安卓和ios統一字段的噩夢,因此會特別注意到符號的使用。剛開始在跟做項目的時候,我的工作就是把大佬們之前趕項目進度時直接使用到的文本放進string裏進行引用。也許是爲了字段內容和IOS的同步,被特意囑咐了一些符號要單獨在代碼之中插入字符,而不是在string中帶入字符。

1.符號在尾部

如要引用的文本內容爲:

當前狀態:

那麼對應的string中就應該寫成:

<string name="current_status">當前狀態</string>
然後在代碼的文本引用中手動加入冒號:

TextView mStatusTv = (TextView)findViewById(R.id.xxxxxx);
(或者註解寫法@BindView(R.id.xxxxxx) TextView mStatusTv;)
mStatusTv.setText(getResource().getString(R.string.current_status) + ":");


2.符號在中間

當我們遇到的文本內容是這樣的時候:(爲了方便我下面都直接用文字而非引用了,但是一定要注意實際開發的時候要用引用的方式去寫)

聯繫我們:xxxxxxxx

像這種內容不變,直接寫死的文本,中間有符號的時候,如無意外我們當然可以直接使用一個字段存起來。但如果要求符號要被提出來的話,下面就是幾個不同的方法了。

可以採取兩段式引用的方法:

<string name="contact_us">聯繫我們</string>
<string name="tel">xxxxxxxx</string>
代碼中:

mTxet.setText("聯繫我們"+":"+"xxxxxx");


或者直接寫在一個字段之中,使用字符串截取進行符號插入:

<string name="contact_us">聯繫我們\\xxxxxx</string><!-- 使用了\作爲位置佔位符,而爲了顯示出\這個符號,必須使用多一個\進行標識,"等符號同理 -->
代碼中:

String str = getResource().getString(R.string.contact_us);
int index = str.indexOf("\\");//得到佔位符/所在的位置
str = str.substring(0, index)+":"+str.substring(index+1);
mText.setText(str);

3.配對符號

同理,遇到配對符號也是一樣的寫法:

生活就像海洋(偷偷插入一下括號),只有意志堅強的人才能到達彼岸。

這種完整的文本我還是比較喜歡寫在一個字段中,使用字符串去截取,畢竟後期如果整理string也比較方便嘛。

<string name="dictum">生活就像海洋\\偷偷插入一下括號\\,只有意志堅強的人才能到達彼岸。</string>
代碼中:

String str = getResource().getString(R.string.dictum);
int firstIndex = str.indexOf("\\");
int lastIndex = str.lastIndexOf("\\");
str = str.substring(0, firstIndex) + "(" + str.substring(firstIndex+1, lastIndex) + ")" + str.substring(lastIndex+1);
mText.setText(str);


4.轉義字符

在string文件中,比較常用到一些用於控制格式或者是無法直接表示出來的符號,我們就會用轉義字符去表示。例如英文符的""、\等。這些符號在string資源文件中進行引用的時候是沒有辦法直接顯示出來的,因此在這些字符前使用反斜槓\進行轉義後,才能正確的顯示出來。

string中:

牆上掛着\"注意安全\"的標誌

使用過程中有任何的建議\\或意見

代碼中引用string資源後顯示:

牆上掛着"注意安全"的標誌

使用過程中有任何的建議\或意見



另外,想要控制格式,插入空格鍵、換行、製表符等,也可以使用轉義字符達到效果。參考c中常使用的一些轉義符:

空格:&#160;

換行:\n

製表符:\t


二、可動態改變固定位置的文本——格式化字符串

有時候我們會遇到這樣的問題:設計稿需要我們將數據插入到一段格式固定的文本之中,例如

歡迎您,xxx老師

對於這種文本處理,最初級的做法就是分成兩段式寫法,也就是:

<string name="welcome">歡迎您,</string>
<string name="teacher">老師</string>
代碼中:

mText.setText(getResource().getString(R.string.welcome) + mTeacherName + getResource().getString(R.string.teacher));

這種寫法當然也能實現這個效果,但是在有龐大的這種類型文本處理上,多次拼接就比較容易出錯。特別是一個文本中有多個動態變量的情況之下,出錯率非常高。爲了應對這種情況,可以使用格式化string進行動態插入數據。

1.單個動態文本替換格式

假設在一段文本之中,只擁有一個動態變量,則我們可以使用以下寫法實現動態插入變量。

<string name="welcome">歡迎您,%s老師</string>
代碼中:

mText.setText(getResource().getString(R.string.welcom, mTeacherName));//mTeacherName是String類型的變量。


我們在字段之中插入的%s是一個佔位符,簡單來說就是一個先在資源中佔着地方,然後允許在引用字段資源的時候再放東西進去替換的好東西。%表示類型,%s也就是string類型。此外,還有%d表示整型,%f表示浮點型。


2.多個動態文本替換格式

假設要實現以下文本,按照上一部分的思路,會怎樣呢?

歡迎您,a老師。您目前積分是b,等級爲c

a、b、c表示三個動態文本,其中ac爲string類型,b爲int類型。


按照單個文本替換的思路,對應的string字段應該是:

<string name = "welcome">歡迎您,%s老師。您目前積分是%d,等級爲%s</string>
而在代碼中引用的時候,按照順序放入對應格式的變量後,編譯時AndroidStudio就會報錯:


Error:(445) Multiple substitutions specified in non-positional format; did you mean to add the formatted="false" attribute?大意就是在非位置格式加入了多個替換,可以理解AndroidStudio並沒有按照我們所排好的變量逐一放進對應占位符中。爲了實現按照位置將文本替換進對應的佔位符中,在多個文本替換的情況之下我們需要使用以下的方式:

<string name = "welcom">歡迎您,%1$s老師。您目前積分是%2$d,等級爲%3$s</string>


在%n$s的格式化string中,%s依舊錶示字符串類型,而n則表示這個字段將被傳入的第幾個文本參數所替換。在引用這個字段的時候,規定了傳入的第一個參數類型是string,將被替換到%1$s的位置上;傳入的第二個參數類型爲int,將被替換到%2$d的位置上;傳入的第三個參數的類型爲string,將被替換到%3$s的位置上。根據這個規則,我們進行試驗一下:

<string name = "welcome_1">歡迎您,%1$s老師。您的積分是%2$d,目前等級爲%3$s</string>
<string name = "welcome_2">歡迎您,%3$s老師。您的積分是%2$d,目前等級爲%1$s</string>
代碼中進行引用:

TextView mText1 = (TextView) findViewById(R.id.test1);
TextView mText2 = (TextView) findViewById(R.id.test2);
mText1.setText(getResource().getString(R.string.welcome_1, "111", 222, "333"));
mText2.setText(getResource().getString(R.string.welcome_2, "111", 222, "333"));

這裏我們傳入一樣的數據,運行之後看看效果:



這種方式同樣適用於單個動態文本替換,因此建議只有一個替換文本的時候也使用這種方式,畢竟統一又好記嘛~


3.空格、留位等更多替換格式

上一部分已經解決了大部分的使用情況了。這裏假設我們需要完成以下文本的話,該怎麼辦呢?

需要支付  236.50  元 (數字與前後文本各間隔2空格距離)

可能想到的字段應該是:

<string name="pay">需要支付  %1$f  元</string><!--手動輸入2個空格-->

在代碼中進行引用:

TextView test = (TextView)findViewById(R.id.test);
test.setText(getResources().getString(R.string.pay, 236.5));

這時候我們得到的內容是:

即數字前後只有一個空格(在string文件中輸入的空格大於1個時只顯示1個),數字保留小數點後6位。


第二個想法是,使用轉義字符&#160;表示空格,如下:

<string name="pay">需要支付&#160;&#160;%1$f&#160;&#160;元</string>
在代碼中進行引用(語句同上),得到內容:


(差別比較小但是還是有差別的!)即數字前後確實兩個空格,數字保留小數點後6位。


爲了解決這個問題,我們可以使用%n$mf。這個格式表示:類型是%f,即浮點類型;引用時使用傳入的第n個參數替換;當m是整數時,表示在數字前空出(m-數字所佔長度)數量的空格;當m是小數時,表示在數字前空出(m的整數部分-數字所佔長度)數量的空格,小數點後保留(m的小數部分)位。下面用一組對比來加深這個記憶:

<string name="pay1">需要支付%1$f元</string>

<string name="pay2">需要支付%1$6f元</string>
<string name="pay3">需要支付%1$10f元</string>
<string name="pay4">需要支付%1$11f元</string>
<string name="pay5">需要支付%1$12f元</string>

<string name="pay6">需要支付%1$.2f元</string>
<string name="pay7">需要支付%1$6.2f元</string>
<string name="pay8">需要支付%1$8.2f元</string>
<string name="pay9">需要支付%1$10.2f元</string>

當在代碼中同樣傳入參數236.5時,得到的結果如下:




※注:在代碼中引用資源(顏色、尺寸、字符串、圖片等)時,都需要通過getResource().getxxx(R.xx.xxx)的格式進行引用。

Activity、Fragment等可以直接拿到上下文對象的:

xx.setText(getResource().getString(R.string.xxxxx));
xx.setColor(getResource().getColor(R.color.xxxxx));

Adapter等這種不能直接引用到資源的,需要引入上下文對象,那我們就可以在構造函數中傳入當前的上下文對象context,通過context去引用對應的資源:

xx.setText(context.getResource().getString(R.string.xxxxx));
xx.setColor(context.getResource().getColor(R.color.xxxxx));

三、同一段文本的不同樣式——SpannableStringBuilder

在ps、word等可以編輯文本的軟件之中,爲了強調或者補充說明,經常會有以下效果:

進一步熟悉英文數據庫的檢索性能與特色。(選做至少2個要求)

加入500ml的水(冷水或者溫水),一直攪拌直至完全溶解。


對於這種做法,最初級的處理方法就是文本拼接,畢竟一段文本無論在xml中設置text屬性或者是在代碼中設置setText,這段文本的統一顏色都取決於textColor屬性所取的值。但是使用拼接就會遇到換行、string資源過於零散等問題。

處理同一段文本的不同樣式,要使用到的類是SpannableStringBuilder。SpannableStringBuilder是一個內容和樣式都可以更改的文本類,並且支持使用append進行內容追加連接、使用insert進行內容插入等。我們先來看看用法。

要實現的效果:

利用MeTeL(國外高校外文多媒體教學資源庫),尋找自己所學專業的相關課程,選擇一門感興趣的課程,瀏覽或下載課程的資源和課件。


string:

<string name="description">利用MeTeL(國外高校外文多媒體教學資源庫),尋找自己所學專業的相關課程,選擇一門感興趣的課程,瀏覽或下載課程的資源和課件。</string>

xml:

<TextView
        android:id="@+id/test1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/description"/>
代碼:

        TextView mText = (TextView) findViewById(R.id.test1);
        SpannableStringBuilder mBuilder = new SpannableStringBuilder();
        mBuilder.append(getResources().getString(R.string.description));
        ForegroundColorSpan mColorSpan = new ForegroundColorSpan(Color.parseColor("#ff0000"));
        mBuilder.setSpan(mColorSpan, 7, 23, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
        mText.setText(mBuilder);


來看看效果:



上面可以看出來,SpannableStringBuilder的setSpan方法就是用於改變文本樣式的。setSpan(Object what, int start, int end, int flags)參數如下:

what——樣式

設置不同的Span添加不同的樣式。上面使用的ForegroundColorSpan表示的是文本顏色。除此以外還有以下樣式:

BackgroundColorSpan ::文本背景色

ForegroundColorSpan:文本顏色

StrikethroughSpan:刪除線

UnderlineSpan:下劃線

StyleSpan:字體樣式:粗體、斜體等

TypefaceSpan :文本字體

還有一些圖片、文本縮放、上標下標、超鏈接、點擊事件等不常用的樣式,需要的時候可以自行百度。


start——文本樣式改變的開始位置

end——文本樣式改變的結束位置(不包括這個位置)

start和end的位置形式是[start,end),即只包括前不包括後。


flags——取值如下(使用insert插入的時候起效果)

Spannable. SPAN_INCLUSIVE_EXCLUSIVE:前面包括,後面不包括。即當insert的文本的位置在[start,end),也就是start到end-1的範圍內時,應用span樣式

Spannable. SPAN_INCLUSIVE_INCLUSIVE:前面包括,後面包括。即當insert的文本的位置在[start,end],也就是start到end的範圍內時,應用span樣式

Spannable. SPAN_EXCLUSIVE_EXCLUSIVE:前面不包括,後面不包括。即當insert的文本的位置在(start,end),也就是start+1到end-1的範圍內時,應用span樣式

Spannable. SPAN_EXCLUSIVE_INCLUSIVE:前面不包括,後面包括。即當insert的文本的位置在(start,end],也就是start+1,end的範圍內時,應用span樣式


定義一個“0123456789”的字符串資源,並令TextView引用。使用setSpan令第3到6位變成紅色。代碼及效果如下:

	TextView mText = (TextView) findViewById(R.id.test);
        String str = mText.getText().toString();
        SpannableStringBuilder mBuilder = new SpannableStringBuilder(str);
        ForegroundColorSpan mColorSpan = new ForegroundColorSpan(Color.parseColor("#ff0000"));
        mBuilder.setSpan(mColorSpan, 3, 7, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
        mText.setText(mBuilder);



現在進行在不同的位置插入字符“-”,對比不同flags參數和不同位置的區別。



使用以上的語句還有一個缺點,就是對於不同的文本,都需要自己確定位置。這時候可以插入標識符,通過str.indexOf()和str.lastIndexOf()定位標識符位置,然後傳入到start和end中。具體標識符定位使用回顧一下 [一.4.轉義字符] 吧。


四、文本的特殊樣式

大部分文本的樣式都可以使用xml的設定完成,如文字顏色、文字樣式(加粗、斜體)、文字大小、文字類型等等。但是有一些特殊樣式是無法在xml中設置的。

1.下劃線

下劃線在UI稿中時不時都會出現。在實習的過程中,我看到我的同事爲了表示下劃線,使用了一個豎直的線性佈局,裏邊放入了TextView和一個當作下劃線使用的View。對於這種做法我感覺有點多此一舉。爲了表示出下劃線,這裏給出兩種方法:

使用html標籤

在對應的string資源的某個文本中,在需要添加下劃線的文本內使用html的下劃線標記<u></u>可以令標記內的文字加上下劃線,如下:

<string name = "underline"><u>下劃線文本</u></string>


也可以在java文件中使用代碼和html標籤進行設置,如下:

TextView mText = (TextView)findViewById(R.id.underline_text);
mText.setText(Html.fromHtml(<u>+getResource().getString(R.string.undeline)+</u>));

使用Paint屬性

mText.getPaint().setFlags(Paint.UNDERLINE_TEXT_FLAG);//下劃線

設置SpannableStringBuilder/SpannableString類的what屬性

String str = mText.getText().toString();
SpannableStringBuilder underline = new SpannableString(str);
underline.setSpan(new UnderLineSpan(), 0, str.length(), Spannable. SPAN_INCLUSIVE_EXCLUSIVE);

2.刪除線

在做一個購買頁面的時候,接到的UI設計稿使用了刪除線表示原價。查詢了一下,實現方法基本和上面下劃線一致。刪除線可以採用以下設置。

使用Paint屬性

mText.getPiant().setFlags(Paint.STRIKE_THRU_TEXT_FLAG);//刪除線


設置SpannableStringBuilder/SpannableString的what屬性

String str = mText.getText().toString();
SpannableStringBuilder underline = new SpannableString(str);
underline.setSpan(new StrikethroughSpan(), 0, str.length(), Spannable. SPAN_INCLUSIVE_EXCLUSIVE);


*********************************************************************************************

很慚愧,這是我實習以來才寫完的第一篇實戰筆記。平時雖然回到宿舍時間也不多,但是也有一些時間可以寫的,也算是懶吧。文本樣式編輯這篇筆記,一開始沒想到會寫這麼長,但是一邊在寫一邊查詢的時候,發現有很多東西查過了資料之後感覺不夠詳細,需要自己驗證結果,結果越拖越久。總的來說第一篇終於結束啦,很高興能看我的日常廢話,比心心。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章