Android 自定義控件實現分散對齊TextView

效果圖:

佈局文件如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        >
        <com.home.JustifyTextView
            android:layout_width="@dimen/dp60"
            android:layout_height="wrap_content"
            android:text="支付時間"
            android:textColor="@color/white"
            android:textSize="@dimen/dp14"
            android:layout_marginLeft="@dimen/dp50"
            />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text=":"
            android:textColor="@color/white"
            android:textSize="@dimen/dp14" />
        <TextView
            android:id="@+id/tv_date_time"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="2019-12-03 14:56"
            android:textColor="@color/white"
            android:textSize="@dimen/dp14" />
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        >
        <com.home.JustifyTextView
            android:layout_width="@dimen/dp60"
            android:layout_height="wrap_content"
            android:text="流水號"
            android:textColor="@color/white"
            android:textSize="@dimen/dp14"
            android:layout_marginLeft="@dimen/dp50"
            />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text=":"
            android:textColor="@color/white"
            android:textSize="@dimen/dp14" />
        <TextView
            android:id="@+id/tv_code"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="20191203145976059"
            android:textColor="@color/white"
            android:textSize="@dimen/dp14" />
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        >
        <com.home.JustifyTextView
            android:layout_width="@dimen/dp60"
            android:layout_height="wrap_content"
            android:text="金額"
            android:textColor="@color/white"
            android:textSize="@dimen/dp14"
            android:layout_marginLeft="@dimen/dp50"
            />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text=":"
            android:textColor="@color/white"
            android:textSize="@dimen/dp14" />
        <TextView
            android:id="@+id/tv_money"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="-64.00元"
            android:textColor="@color/red"
            android:textSize="@dimen/dp14" />
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        >
        <com.home.JustifyTextView
            android:layout_width="@dimen/dp60"
            android:layout_height="wrap_content"
            android:text="對方賬號"
            android:textColor="@color/white"
            android:textSize="@dimen/dp14"
            android:layout_marginLeft="@dimen/dp50"
            />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text=":"
            android:textColor="@color/white"
            android:textSize="@dimen/dp14" />
        <TextView
            android:id="@+id/tv_remote_account"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="青春餵了狗"
            android:textColor="@color/white"
            android:textSize="@dimen/dp14" />
    </LinearLayout>

</LinearLayout>

 

核心重點在JustifyTextView這個類,實現如下:

 

package com.home;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.util.AttributeSet;

public class JustifyTextView extends android.support.v7.widget.AppCompatTextView {
    public static final String TAG = JustifyTextView.class.getSimpleName();

    private Paint paint = new Paint();
    private Rect rect_0 = new Rect();
    private Rect rect_l = new Rect();
    private Rect rect_tmp = new Rect();
    public JustifyTextView(Context context) {
        super(context);
    }

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

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

    @Override
    protected void onDraw(Canvas canvas)
    {
        CharSequence cs = getText();
        String txt = null;
        if(cs == null)
            txt = "";
        else
            txt = cs.toString();
        if(txt.length() == 0)
            super.onDraw(canvas);
        else
        {
            float textSize = getTextSize();
            Typeface typeface = getTypeface();
            int color = getCurrentTextColor();

            int w = getWidth();
            int h = getHeight();
            int l = getPaddingLeft();
            int r = w - getPaddingRight();
            int t = getPaddingTop();
            int b = h - getPaddingBottom();
            paint.setAntiAlias(true);
            paint.setTypeface(typeface);
            paint.setTextSize(textSize);
            paint.setTextAlign(Paint.Align.LEFT);
            paint.setColor(color);
            int centerY = (b + t) / 2;
            Paint.FontMetrics fontMetrics = paint.getFontMetrics();
            float y = centerY + (fontMetrics.descent - fontMetrics.ascent) / 2- fontMetrics.descent; // 垂直方向也居中;
            paint.getTextBounds(txt, 0, 1, rect_0);   // 獲取第一個字符的大小
            paint.getTextBounds(txt, 0, 1, rect_l);   // 獲取最後一個字符的大小
            float space = (r - l - (rect_0.width() * 0.5f) - (rect_l.width() * 0.5f)) / (txt.length() - 1);
            for(int i = 0, iMax = txt.length(); i < iMax; ++i)
            {
                float x = 0;
                if(i == 0)
                    x = l;
                else if(i == iMax - 1)
                    x = r - rect_l.width();
                else
                {
                    paint.getTextBounds(txt, i, i + 1, rect_tmp);   // 獲取每一個字符的大小
                    x = l + rect_0.width() * 0.5f + i * space - rect_tmp.width() * 0.5f;
                }
                canvas.drawText(txt, i, i + 1, x, y, paint);
            }
        }
    }
}

大概解釋一下中間幾個重點:

一、主要的思路:首先確定最左側一個字符緊貼繪製區域最左側,左右側一個字符緊貼繪製區域最右側,中間的字符在繪製區域中間的空白部分,中心點均勻分佈,讓任意相鄰的兩個字符中心點距離相等。大概圖示如下:

短豎線表示字符中心點,對應代碼中x變量,中間橫線爲一個字符的區域(這個區域大於等於字符實際寬度),對應代碼中的space變量

二、關於x以及space的計算中經常出現的width*0.5f,之所以出現width*0.5f是因爲代碼裏面設置了paint.setTextAlign(Paint.Align.LEFT);這樣一來drawText繪製的時候,對於x座標就都是以字符左側爲標準,而我們確定字符位置都是根據中心點,於是就經常出現減去width*0.5f的情況

三、關於y座標的計算:

float y = centerY + (fontMetrics.descent - fontMetrics.ascent) / 2- fontMetrics.descent; // 垂直方向也居中;

這段代碼是之前寫另外一個控件的時候,從網上某篇帖子裏面摘抄的,時間太久,找不到原文了。關於這段代碼的具體含義,尚不清楚,只知道它能讓文本垂直居中。

四、關於一些bug:

經測試,對於純中文或純英文情況下效果很好,中英混輸情況下,就出現很大的偏差,目前還不知道爲什麼,暫時效果滿足,以後想起來再想辦法修復

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