Android文本排版实现

        在项目中有一个小功能需要实现,就是对多行文本进行排版布局,每一行的内容又分为两部分,左边为标题,右边为描述,左边内容长度不确定,右边的内容需要对齐,如有换行也需要对齐右边的文本。

效果图

       效果图如下图所示:

这里写图片描述

       可以看到内容分成了两部分,左边的颜色与右边不一致,右边的描述文案统一对齐。

实现方案

       以上功能,由于输入内容输入行数不确定,并且左边的文案长度也不确定,因此不能直接在布局中实现,基于此这里主要实现了以下6种方式

方案1

       采用自定义控件的方式,继承TextView,重新onDraw函数,实现如下:


/**
 * 计算出左边最长的显示字符串maxLeftWidth,之后draw每一行字符,右边的描述从maxLeftWidth开始draw
 * 当一行显示不完全时,折行并且空出maxLeftWidth的空格长度
 */
public class TypographyView1 extends TextView {
   

    private Paint leftPaint = new Paint();
    private Paint rightPaint = new Paint();
    private int fullWidth;
    private float textSize;
    private JSONArray array;
    private int middlePadding = 0;
    float maxLeftWidth = 0;
    int itemSize = 0;

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

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

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

    private void init() {
        textSize = getResources().getDimensionPixelSize(R.dimen.text_size_13);
        leftPaint.setAntiAlias(true);
        leftPaint.setTextSize(textSize);
        leftPaint.setColor(getResources().getColor(R.color.color_black_999999));
        rightPaint.setAntiAlias(true);
        rightPaint.setTextSize(textSize);
        rightPaint.setColor(getResources().getColor(R.color.color_black));
        middlePadding = getResources().getDimensionPixelSize(R.dimen.padding_value);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        fullWidth = getWidth();// 整个textView的宽度
    }

    public void setText(JSONArray array) {
        this.array = array;
        if (array != null) {
            try {
                int size = itemSize = array.length();
                for (int i = 0; i < size; ++i) {
                    JSONArray o = (JSONArray) array.get(i);
                    String key = o.getString(0);
                    String value = o.getString(1);
                    if (TextUtils.isEmpty(key) || TextUtils.isEmpty(value)) {
                        itemSize--;
                        continue;
                    }
                    float curWidth = leftPaint.measureText(key);
                    if (curWidth > maxLeftWidth) {
                        maxLeftWidth = curWidth;
                    }
                }
                maxLeftWidth = maxLeftWidth + middlePadding;
                invalidate();
            } catch (Exception e) {

            }
        }
    }

    boolean setHeight = false;

    @Override
    protected void onDraw(Canvas canvas) {
        if (array == null) {
            return;
        }
        int lineCount = 0;
        try {
            JSONArray item;
            float offsetY;
            for (int i = 0; i < itemSize; ++i) {
                item = (JSONArray) array.get(i);
                offsetY = (lineCount + 1) * textSize;
                canvas.drawText(item.getString(0), 0, offsetY, leftPaint);

                String value = item.getString(1);
                float valueWidth = rightPaint.measureText(value);
                if (valueWidth > fullWidth - maxLeftWidth) {
  // 一行显示不完
                    char[] textCharArray = value.toCharArray();
                    float charWidth;
                    float drawWidth = maxLeftWidth;
                    for (int j = 0; j < textCharArray.length; j++) {
                        charWidth = rightPaint.measureText(textCharArray, j, 1);
                        if (fullWidth - drawWidth < charWidth) {
                            lineCount++;
                            drawWidth = maxLeftWidth;
                            offsetY += textSize;
                        }
                        canvas.drawText(textCharArray, j, 1, drawWidth, offsetY, rightPaint);
                        drawWidth += charWidth;
                    }
                } else {
                    canvas.drawText(value, maxLeftWidth, offsetY, rightPaint);
                }
                lineCount += 2;
            }
            if (!setHeight) {
                setHeight((lineCount + 1) * (int) textSize);
                setHeight = true;
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }
}

       添加了setText(JSONArray array)作为数据输入,并且在这里面测量了左边title的最大宽度,之后调用invalidate触发重绘,在onSizeChanged获取整个控件的宽度,重绘会调用onDraw函数,这里不需要调用super函数,TextView的onDraw函数做了非常多的操作,解析传入的数据,分别一行一行调用canvas来进行drawText操作,当绘制描述时,先计算宽度,如果超过剩余控件说明需要换行,最后调用setHeight设置高度,这个加一个判断条件,因为会触发requestLayout()进行重新布局和invalidate()进行重绘,如果不加判断会一直重绘。

方案2

       方式2与方式1差不多,不同为所有计算都在onDraw函数中:

/**
 * 该方式与方式1很类似,只是所有的计算都放在了onDraw方法中。
 */
public class TypographyView2 extends TextView {
   

    private Paint paint1 = new Paint();
    private Paint paint2 = new Paint();
    private int middlePadding = 0;
    int width;
    private float textSize;
    private JSONArray array;

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

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

    public TypographyView2(Co
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值