Android 自定义控件实现分散对齐TextView

Android 专栏收录该内容
1 篇文章 0 订阅

效果图:

布局文件如下:

<?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:

经测试,对于纯中文或纯英文情况下效果很好,中英混输情况下,就出现很大的偏差,目前还不知道为什么,暂时效果满足,以后想起来再想办法修复

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值