仿微信朋友圈TextView点击查看更多

仿微信朋友圈TextView点击查看更多_第1张图片
效果图如上。需求是文本设置最大显示的行数,未超过最大行数时,有多少内容显示多少内容,超过最大行数时只显示最大行数,并在最后一行末尾添加自定义文本如…展开…点击查看更多等。
实现思路

  1. 继承TextView,拿原始要显示的行数和设置的最大行数最对比。
  2. 运用TextPaint计算出自定义文本的长度。
  3. 运用Layout和TextUtils得出最后一行要显示的文本和前面行的文本。
  4. 最后拼接成SpannableStringBuilder设置到TextView。

代码如下

package com.hai.test.widget;
import android.content.Context;
import android.text.Layout;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.style.ForegroundColorSpan;
import android.util.AttributeSet;
import androidx.appcompat.widget.AppCompatTextView;
import com.hai.test.R;

/**
 * 点击查看更多TextView  借鉴https://www.jianshu.com/p/f4f99eb932d4做了优化
 * Created by huanghp on 2019/12/9.
 * Email [email protected]
 */
public class TailTextView extends AppCompatTextView {
    private boolean showTail = true;
    private boolean isEllipsed = false;
    private static final String LINE_BREAKER = "\n";
    private String tailText = "…查看全文";

    public TailTextView(Context context) {
        this(context, null);
    }

    public TailTextView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

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

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //不显示小尾巴或者已经处理过的不再处理
        if (!showTail || isEllipsed) {
            return;
        }
        int lineCount = getLineCount();
        Layout layout = getLayout();
        int maxLines = getMaxLines();
        //行数没有到maxLines不处理
        if (maxLines == 0 || lineCount < maxLines || TextUtils.isEmpty(getText())) ;
        else {
            int lineEndIndex = layout.getLineEnd(maxLines - 1);//第maxLines行的首字符offset
            int lineStartIndex = layout.getLineStart(maxLines - 1);//第(maxLines - 1)行的首字符offset
            if (lineEndIndex >= getText().length()) return;

            CharSequence mustShowText = getText().subSequence(0, lineStartIndex);
            float tailWidth = getPaint().measureText(tailText);
            CharSequence lastLineText;
            //最后一个字是个换行符就把这个换行符去掉,不然不能在那一行后面增加文字了
            if (LINE_BREAKER.equals(String.valueOf(getText().charAt(lineEndIndex - 1)))) {
                lastLineText = getText().subSequence(lineStartIndex, lineEndIndex - 1);
            } else {
                lastLineText = getText().subSequence(lineStartIndex, lineEndIndex);
            }
            int availableWidth = getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
            CharSequence ellipsizeLastLineText = TextUtils.ellipsize(lastLineText, getPaint(), availableWidth - tailWidth,
                    TextUtils.TruncateAt.END);
            if (ellipsizeLastLineText.length() > 2 && ellipsizeLastLineText != lastLineText) {
                lastLineText = ellipsizeLastLineText.subSequence(0, ellipsizeLastLineText.length() - 1);
            }
            SpannableStringBuilder ssb = new SpannableStringBuilder(mustShowText);
            ssb.append(lastLineText).append(tailText);
            ssb.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.colorAccent)), ssb.length() - tailText.length(), ssb.length(),
                    Spannable.SPAN_INCLUSIVE_INCLUSIVE);
            setText(ssb);
            //重置一下这个位
            isEllipsed = false;
        }
    }
}

重要的地方都有注释,相信大家一看就明白。
说明一下,大家拿到他还可以进行扩展,比如通过自定义属性设置自定义文本、设置自定义文本的颜色以及自定义文本的点击事件,让用起来更方便。

你可能感兴趣的:(android自定义view)