Android 自定义View实现文本流布局

一.前言

一个项目中有一个需求:很多个TextView按照从左到右,从上到下依次排列,如下图所示:

这里写图片描述

这种效果叫做流式布局,在网上查了一下流布局,发现基本都是通过继承ViewGroup来实现的,所以想通过自定义View来实现一个流式布局效果的TextView。

二.要点

观察我们的效果图,发现有如下要点:
1. 流布局的实现
2. 添加点击事件
3. 点击文本块后有水波纹效果

三.实现

1.流布局的实现:

自定义一个View,名为FlowTextView,继承自View。首先需要计算View的大小,宽度很简单,这里就不多过描述,麻烦的是高度的计算。看效果图,不难发现每块文本的高度是一样的,所以View的高度应该是:

height = textHeight * row + spacingVertical * (row-1) + paddingTop + paddingBottom
其中:
row : 行数
textHeight:文本高度;
spacingVertical:文本垂直间距;
paddingTop、paddingBottom:View的上下Padding

<1>.计算文字的高度

这里是将画笔paint设置好字体大小和字体后,通过Paint的FontMetrics来计算文字的高度。

    private void calculateTextHeightAndBaselineY() {
        mPaint.setTextSize(mTxtSize);
        if (mTypeface != null)
            mPaint.setTypeface(mTypeface);
        Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
        mTxtHeightMax = (float) Math.ceil(fontMetrics.descent - fontMetrics.ascent) 
                + mTxtPaddingTop + mTxtPaddingBottom;
    }

<2>.计算view的高度、文本块坐标

复写onMeasure方法。获取view的宽度,遍历所有文本,获取文本的宽度,累积相加,超过View的宽度时换行,记录行数和文本坐标。重复以上动作,直到文本遍历完毕,进而计算view高度。需要注意的是当单个文本的长度超过View的宽度时,需要对该个文本做特殊处理。如,截取文本,使文本在文本后添加“…”等。

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        calculateTextHeightAndBaselineY();
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int height = 0;
        int actualWidth = widthSize - getPaddingRight();                        //获取可绘制的最大宽度
        if (actualWidth > 0) {
            //计算总高度
            height = initTextListPoint(actualWidth);
        }
        setMeasuredDimension(widthSize, height);
    }

     /**
     * 初始化文本坐标区间,计算View高度
     *
     * @param maxX 最大横坐标
     * @return view的高度
     */
    private int initTextListPoint(int maxX) {
        int x = getPaddingLeft();
        int height = 0;
        int rows = 1;
        int drawMaxWidth = (int) (maxX - getPaddingLeft() - mTxtPaddingLeft - mTxtPaddingRight);     //绘制的最大宽度
        mRow.append(0, 0);
        mTextPoints = new Rect[mTextList.length];
        for (int i = 0; i < mTextList.length; i++) {
            String text = mTextList[i];
            mPaint.getTextBounds(text, 0, text.length(), mBound);
            int w = (int) mPaint.measureText(text);    //计算该文本的长度

            
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值