android 自定義兩邊對其的文本框

前言

不久之前,本菜雞遇到了一個需求缩功。android中文本展示需要兩邊對其的效果晴及。于是乎,我就想這種常用的屬性嫡锌,我們的textView居虑稼!然!沒势木!有动雹!無奈,只能吭哧吭哧的谷歌跟压,百度胰蝠。最終,尋得一方,來治我的蠢病茸塞。


正文

網(wǎng)上的各位大神為了實現(xiàn)兩邊對其躲庄,大家也算是腦洞大開,大致上為使用空格填充钾虐,或者將所有字符統(tǒng)一大小來實現(xiàn)兩邊對其噪窘。這種做法雖然很簡單,但是只能應(yīng)付一些單純的場景效扫。一旦場景復(fù)雜起來就會顯露弊端倔监。例如文字間距忽大忽小,句末文字沒有貼邊等一些問題菌仁。俗話說得好浩习,撿最貴的飲料瓶,裝最精致的逼济丘。這么粗糙的方法當(dāng)然不能忍受谱秽。那么有沒有方法來解決以上問題呢?當(dāng)然是有的:

兩邊對其原理

其實原理很簡單摹迷,首先先得到我們要顯示文本的文本框的寬度疟赊。隨后計算出一行最多能夠容納多少個文字,然后讀取文本峡碉,將文本繪制在TextView上近哟,在繪制之前計算出當(dāng)前行的長度減去本行最大容納文字的總長度,最后將這些長度均攤到這一行所有的文字間隔中鲫寄,這樣就可以達(dá)到吉执,收尾貼邊,并且整行文字間隔相等的狀態(tài)塔拳。詳細(xì)的內(nèi)容都寫在代碼注釋里鼠证,直接看代碼即可峡竣。

代碼

package com.flyme.systemuitools.gameassiant.gamemode.view;

import android.content.Context;
import android.graphics.Canvas;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.widget.TextView;


public class DroidAlignTextView extends TextView {
    private int mLineY = 0;//總行高
    private int mViewWidth;//TextView的總寬度
    private TextPaint paint;
    private boolean isEnter;

    public DroidAlignTextView(Context context) {
        super(context);
        init();
    }

    public DroidAlignTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public DroidAlignTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        paint = getPaint();
        paint.setColor(getCurrentTextColor());
        paint.drawableState = getDrawableState();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        mViewWidth = getMeasuredWidth() - 5;//獲取textview的實際寬度
        mLineY = 0;
        mLineY += getTextSize();

        String text = getText().toString();

        Layout layout = getLayout();
        int lineCount = layout.getLineCount();
        for (int i = 0; i < lineCount; i++) {//每行循環(huán)
            int lineStart = layout.getLineStart(i);
            int lineEnd = layout.getLineEnd(i);
            String lineText = text.substring(lineStart, lineEnd);//獲取TextView每行中的內(nèi)容
            if (needScale(lineText)) {

                if(isEnter){
                    lineStart += 1;
                    lineText = lineText.substring(1, 1 + lineText.length() - 1);
                    isEnter = false;
                }

                if (i == lineCount - 1) {//最后一行不需要重繪
                    canvas.drawText(lineText, 0, mLineY, paint);
                } else {
                    float width = StaticLayout.getDesiredWidth(text, lineStart, lineEnd, paint);
                    drawScaleText(canvas, lineText, width);
                }
            } else {

                if (isEnter && !lineText.equals("\n")) {
                    lineText = lineText.substring(1, 1 + lineText.length() - 1);
                    isEnter = false;
                }

                if (lineText.charAt(lineText.length() - 1) == '\n') {
                    isEnter = true;
                }

                canvas.drawText(lineText, 0, mLineY, paint);
                if(lineText.equals("\n")){
                    mLineY -= 8*3;
                }
            }
            mLineY += getLineHeight();//寫完一行以后靠抑,高度增加一行的高度
        }
    }

    /**
     * 重繪此行.
     *
     * @param canvas    畫布
     * @param lineText  該行所有的文字
     * @param lineWidth 該行每個文字的寬度的總和
     */
    private void drawScaleText(Canvas canvas, String lineText, float lineWidth) {
        float x = 0;
        if (isFirstLineOfParagraph(lineText)) {
            String blanks = "  ";
            canvas.drawText(blanks, x, mLineY, paint);
            float width = StaticLayout.getDesiredWidth(blanks, paint);
            x += width;
            lineText = lineText.substring(1, 1+2);
        }
        //比如說一共有5個字,中間有4個間隔适掰,
        //那就用整個TextView的寬度 - 5個字的寬度颂碧,
        //然后除以4,填補(bǔ)到這4個空隙中
        float interval = (mViewWidth - lineWidth) / (lineText.length() - 1);
        for (int i = 0; i < lineText.length(); ) {
            String character = "";
            if (!isEmojiCharacter(lineText.charAt(i))) {
                // 是emoji表情
                character = String.valueOf(lineText.substring(i, i += 2));
            } else {
                character = String.valueOf(lineText.charAt(i++));
            }
            float cw = StaticLayout.getDesiredWidth(character, paint);
            canvas.drawText(character, x, mLineY, paint);
            x += (cw + interval);

        }
    }


    /**
     * 判斷是不是段落的第一行.
     * 一個漢字相當(dāng)于一個字符类浪,此處判斷是否為第一行的依據(jù)是:
     * 字符長度大于3且前兩個字符為空格
     *
     * @param lineText 該行所有的文字
     */
    private boolean isFirstLineOfParagraph(String lineText) {
        return lineText.length() > 3 && lineText.charAt(0) == ' ' && lineText.charAt(1) == ' ';
    }

    /**
     * 判斷需不需要縮放.
     *
     * @param lineText 該行所有的文字
     * @return true 該行最后一個字符不是換行符  false 該行最后一個字符是換行符
     */
    private boolean needScale(String lineText) {
        if (lineText.length() == 0 || lineText.charAt(lineText.length() - 1) == '\n') {
            return false;
        } else {
            return true;
        }
    }

    /**
     * 判斷是否是Emoji
     *
     * @param codePoint 比較的單個字符
     * @return
     */
    private boolean isEmojiCharacter(char codePoint) {
        return (codePoint == 0x0) || (codePoint == 0x9) || (codePoint == 0xA) ||
                (codePoint == 0xD) || ((codePoint >= 0x20) && (codePoint <= 0xD7FF)) ||
                ((codePoint >= 0xE000) && (codePoint <= 0xFFFD)) || ((codePoint >= 0x10000)
                && (codePoint <= 0x10FFFF));
    }
}


?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末载城,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子费就,更是在濱河造成了極大的恐慌诉瓦,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異睬澡,居然都是意外死亡固额,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進(jìn)店門煞聪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來斗躏,“玉大人,你說我怎么就攤上這事昔脯∽牟冢” “怎么了?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵云稚,是天一觀的道長隧饼。 經(jīng)常有香客問我,道長碱鳞,這世上最難降的妖魔是什么桑李? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮窿给,結(jié)果婚禮上贵白,老公的妹妹穿的比我還像新娘。我一直安慰自己崩泡,他們只是感情好禁荒,可當(dāng)我...
    茶點故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著角撞,像睡著了一般呛伴。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上谒所,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天热康,我揣著相機(jī)與錄音,去河邊找鬼劣领。 笑死姐军,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的尖淘。 我是一名探鬼主播奕锌,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼村生!你這毒婦竟也來了惊暴?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤趁桃,失蹤者是張志新(化名)和其女友劉穎辽话,沒想到半個月后肄鸽,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡油啤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年贴捡,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片村砂。...
    茶點故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡烂斋,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出础废,到底是詐尸還是另有隱情汛骂,我是刑警寧澤,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布评腺,位于F島的核電站帘瞭,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏蒿讥。R本人自食惡果不足惜蝶念,卻給世界環(huán)境...
    茶點故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望芋绸。 院中可真熱鬧媒殉,春花似錦、人聲如沸摔敛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽马昙。三九已至桃犬,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間行楞,已是汗流浹背攒暇。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留子房,地道東北人形用。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像池颈,于是被迫代替她去往敵國和親尾序。 傳聞我的和親對象是個殘疾皇子钓丰,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,092評論 2 355

推薦閱讀更多精彩內(nèi)容