Android 自定义指定省略号位置的TextView

系统默认的文本省略方式无法满足特定需求,本文介绍如何在Android中创建一个自定义TextView,能指定省略号的位置并适应包含表情的文本。通过设置属性`ellipsize_text`和`ellipsize_index`,可以实现自定义省略效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

系统自带文本省略位置只有开始、中间、末尾,不适用指定省略号后显示几位字符的情况,适配含各种表情符号。

<declare-styleable name="EllipsizeTextView">
     <attr name="ellipsize_text" format="string|reference" />
     <attr name="ellipsize_index" format="integer|reference" />
</declare-styleable>

public class MyEllipsizeTextView extends AppCompatTextView {

    private static final String DEFAULT_ELLIPSIZE_TEXT = "...";
    private static final int DEFAULT_ELLIPSIZE_INDEX = 7;

    private CharSequence mEllipsizeText;
    private CharSequence mOriginText;

    private int mMaxLines;
    private int mEllipsizeIndex;

    public MyEllipsizeTextView(Context context) {
        super(context);
    }

    public MyEllipsizeTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.EllipsizeTextView);
        mEllipsizeText = ta.getText(R.styleable.EllipsizeTextView_ellipsize_text);
        mEllipsizeIndex = ta.getInt(R.styleable.EllipsizeTextView_ellipsize_index, DEFAULT_ELLIPSIZE_INDEX);

        if (mEllipsizeText == null) {
            mEllipsizeText = DEFAULT_ELLIPSIZE_TEXT;
        }
        ta.recycle();
    }

    public MyEllipsizeTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setText(mOriginText);
    }

    @Override
    public void setMaxLines(int maxLines) {
        if (mMaxLines != maxLines) {
            super.setMaxLines(maxLines);
            mMaxLines = maxLines;
        }
    }

    @Override
    public void setText(CharSequence text, BufferType type) {
        mOriginText = text;
        int maxLineCount = Math.max(1, mMaxLines);
        String content = getEllipsizeString((String) text, maxLineCount);
        super.setText(content, type);
    }

    private int getContentWidth() {
        Layout layout = getLayout();
        if (layout != null) {
            return layout.getWidth() - getPaddingLeft() - getPaddingRight();
        }
        return -1;
    }
    
    private String getEllipsizeString(String originText, int maxLines) {
        int textLength = originText.length();
        TextPaint mPaint = getPaint();
        float width = getContentWidth() - mPaint.measureText(originText.substring(0, 1));
        float totalWidth = width * maxLines;
        MeasuredText text = new Builder(originText.toCharArray()).appendStyleRun(mPaint, textLength, true).build();
        if (totalWidth > text.getWidth(0, textLength ) || width < 0) {
            return originText;
        }
        int rightIndex = textLength - mEllipsizeIndex;
        do {
            if (text.getCharWidthAt(rightIndex) == 0) {
                rightIndex--;
            }
        } while (text.getCharWidthAt(rightIndex) == 0);
        float endWidth = mPaint.measureText((String) mEllipsizeText) + text.getWidth(rightIndex,
                textLength );
        char[] copiedBuffer = new char[textLength ];
        TextUtils.getChars(originText, 0, textLength , copiedBuffer, 0);
        StringBuilder sb = new StringBuilder();
        int lastLeftIndex = 0;
        int leftIndex = 0;
        float textWidth;
        for (int i = 0; i < maxLines; i++) {
            if (i == maxLines - 1) {
                textWidth= width - endWidth;
            } else {
                textWidth= width;
            }
            while (leftIndex < textLength ) {
                textWidth-= text.getCharWidthAt(leftIndex);
                if (textWidth < 0.0f) {
                    break;
                }
                leftIndex++;
            }
            while (leftIndex > 0 && copiedBuffer[leftIndex - 1] == ' ') {
                leftIndex--;
            }
            sb.append(originText.substring(lastLeftIndex, leftIndex));
            lastLeftIndex = leftIndex;
            if (i < maxLines - 1) {
                sb.append("\n");
            }
        }
        sb.append(mEllipsizeText);
        sb.append(originText.substring(rightIndex, textLength));
        return sb.toString();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值