Android AutoWrapTextView中英文排版問題的解決方法
前言
最近項目有新需求,UED給了個卡券密碼的UI樣式,如圖:

我一看很簡單啊,一個TextView解決問題,然后做好以后在模擬器里一看.....

納尼,這個時候才想起來,TextView 中英文在一起會有排版問題,那怎么解決呢......
思路
剛開始的想法是一個字符一個字符的去繪制,繪制到最右邊的臨界點就換行繪制,結果實踐以后發(fā)現(xiàn)不同的字符之間的間距不一樣,顯示會非常凌亂,又沒有什么好的方案解決這個間距問題,所以這個方案pass;單個字符繪制不行那就一行一行繪制,根據(jù)View的長度把文本拆分成N行,然后一行一行的繪制。
實現(xiàn)
首先創(chuàng)建一個繼承自View的AutoWrapTextView
public class AutoWrapTextView extends View {
}
來看看它的構造方法
public AutoWrapTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
initStyle(context, attrs);
initPaint();
}
init方法里分別調(diào)用了initStyle方法和initPaint方法;
initStyle方法主要解析自定義的屬性
private void initStyle(Context context, AttributeSet attrs) {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.AutoWrapTextViewStyle);
mPaddingLeft = typedArray.getDimensionPixelSize(R.styleable.AutoWrapTextViewStyle_paddingLeft, 0);
mPaddingRight = typedArray.getDimensionPixelSize(R.styleable.AutoWrapTextViewStyle_paddingRight, 0);
mPaddingTop = typedArray.getDimensionPixelSize(R.styleable.AutoWrapTextViewStyle_paddingTop, 0);
mPaddingBottom = typedArray.getDimensionPixelSize(R.styleable.AutoWrapTextViewStyle_paddingBottom, 0);
mTextColor = typedArray.getColor(R.styleable.AutoWrapTextViewStyle_textColor, Color.BLACK);
mTextSize = typedArray.getDimensionPixelSize(R.styleable.AutoWrapTextViewStyle_textSize, 50);
mLineSpacingExtra = typedArray.getInteger(R.styleable.AutoWrapTextViewStyle_lineSpacingExtra, 7);
typedArray.recycle();
}
屬性名含義都很明顯不用過多解釋,initPaint方法就是初始化一個文本畫筆
private void initPaint() {
mTextPaint = new TextPaint();
mTextPaint.setAntiAlias(true);
mTextPaint.setTextSize(mTextSize);
mTextPaint.setColor(mTextColor);
mTextPaint.setTextAlign(Paint.Align.LEFT);
}
接下來我們看看設置文本的方法setText方法
public void setText(String text) {
if (TextUtils.isEmpty(text)) return;
//把文本轉(zhuǎn)換成Char數(shù)組
mTextCharArray = text.toCharArray();
requestLayout();
}
首先把文本轉(zhuǎn)換成Char數(shù)組,然后循環(huán)數(shù)組把整個文本拆分成N行文本,下面來看看核心方法splitText方法
private void splitText(int heightMode) {
if (mTextCharArray == null) return;
mSplitTextList = new ArrayList<>();
mSingleTextWidth = getMeasuredWidth() - mPaddingLeft - mPaddingRight;
int currentSingleTextWidth = 0;
StringBuffer lineStringBuffer = new StringBuffer();
for (int i = 0, length = mTextCharArray.length; i < length; i++) {
char textChar = mTextCharArray[i];
currentSingleTextWidth += getSingleCharWidth(textChar);
if (currentSingleTextWidth > mSingleTextWidth) {
mSplitTextList.add(lineStringBuffer.toString());
lineStringBuffer = new StringBuffer();
currentSingleTextWidth = 0;
i--;
} else {
lineStringBuffer.append(textChar);
if (i == length - 1) mSplitTextList.add(lineStringBuffer.toString());
}
}
int textHeight = 0;
mSplitTextRectArray = new Rect[mSplitTextList.size()];
for (int m = 0, length = mSplitTextList.size(); m < length; m++) {
String lineText = mSplitTextList.get(m);
Rect lineTextRect = new Rect();
mTextPaint.getTextBounds(lineText, 0, lineText.length(), lineTextRect);
if (heightMode == MeasureSpec.AT_MOST) {
textHeight += (lineTextRect.height() + mLineSpacingExtra);
if (m == length - 1) {
textHeight = textHeight + mPaddingBottom + mPaddingTop;
}
} else {
if (textHeight == 0)
textHeight = getMeasuredHeight();
}
mSplitTextRectArray[m] = lineTextRect;
}
setMeasuredDimension(getMeasuredWidth(), textHeight);
}
首先創(chuàng)建一個屬性名為mSplitTextList的List集合用來存放拆分的文本;
mSingleTextWidth 為單行文本顯示的寬度;
currentSingleTextWidth 為當前一行累計計算的寬度;
然后開始循環(huán)Char數(shù)組,getSingleCharWidth方法就是計算單個Char的寬度;
如果currentSingleTextWidth 小于 mSingleTextWidth 就把Char添加到lineStringBuffer 當中,如果是最后一個Char就直接把lineStringBuffer添加到mSplitTextList集合當中
如果currentSingleTextWidth 大于 mSingleTextWidth,就把lineStringBuffer添加到mSplitTextList集合當中,重新給lineStringBuffer賦值,currentSingleTextWidth 歸0;
循環(huán)結束以后拆分好的文本就都添加到mSplitTextList集合當中了。
拆分完成以后循環(huán)mSplitTextList集合,得到每一行文本的Rect值,繪制文本的時候會用到,然后設置View的寬高。
接下來就是繪制方法drawText
public void drawText(Canvas canvas) {
if (mSplitTextList == null || mSplitTextList.size() == 0) return;
int marginTop = getTopTextMarginTop();
for (int m = 0, length = mSplitTextList.size(); m < length; m++) {
String lineText = mSplitTextList.get(m);
canvas.drawText(lineText, mPaddingLeft, marginTop, mTextPaint);
marginTop += (mSplitTextRectArray[m].height() + mLineSpacingExtra);
}
}
首先得到第一行文本距離頂部的高度marginTop,然后循環(huán)文本繪制每一行文本內(nèi)容。
效果圖
我們來看下最后的效果

結束語
至此整個類的邏輯分析就結束了,想看完整源碼的可以移步:https://github.com/chenpengfei88/AutoWrapTextView或者通過本地進行下載:http://xiazai.jb51.net/201705/yuanma/AutoWrapTextView(jb51.net).rar
好了,以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
- Android用戶輸入自動提示控件AutoCompleteTextView使用方法
- Android自動獲取輸入短信驗證碼庫AutoVerifyCode詳解
- Android中使用 AutoCompleteTextView 實現(xiàn)手機號格式化附帶清空歷史的操作
- Android自動編輯文本框(AutoCompleteTextView)使用方法詳解
- Android中AutoCompleteTextView自動提示
- Android仿新浪微博oauth2.0授權界面實現(xiàn)代碼(2)
- android中AutoCompleteTextView的簡單用法(實現(xiàn)搜索歷史)
- Android仿百度谷歌搜索自動提示框AutoCompleteTextView簡單應用示例
- 關于Android HTML5 audio autoplay無效問題的解決方案
- Android AutoCompleteTextView自動提示文本框?qū)嵗a
- Android App開發(fā)的自動化測試框架UI Automator使用教程
- Android中AutoCompleteTextView與TextWatcher結合小實例
- Android AutoValue使用和擴展庫
相關文章
Android自定義View實現(xiàn)仿駕考寶典顯示分數(shù)效果(收藏)
本文通過自定義view和屬性動畫結合在一起實現(xiàn)實現(xiàn)仿駕考寶典顯示分數(shù)效果,非常不錯,具有參考借鑒價值,需要的的朋友參考下2017-03-03
Android自定義View實現(xiàn)內(nèi)存清理加速球效果
這篇文章主要為大家詳細介紹了Android自定義View實現(xiàn)內(nèi)存清理加速球的效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-02-02
Android IPC機制ACtivity綁定Service通信代碼實例
這篇文章主要介紹了Android IPC機制ACtivity綁定Service通信代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-09-09
Android 實現(xiàn)左滑出現(xiàn)刪除選項
滑動刪除的部分主要包含兩個部分, 一個是內(nèi)容區(qū)域(用于放置正常顯示的view),另一個是操作區(qū)域(用于放置刪除按鈕)。下面通過本文給大家介紹Android 實現(xiàn)左滑出現(xiàn)刪除選項,需要的朋友可以參考下2017-06-06

