返回

Android 可折叠TextView:释放文本的无限可能

Android

Android 可折叠TextView:让你的文本随心所欲

技术在不断进步,而 Android 也不例外。作为移动应用开发领域的主流平台,Android 始终致力于为开发者提供强大的工具和功能,让其打造出创新且用户友好的应用。其中,TextView 组件便是 Android UI 中不可或缺的一部分,它负责显示文本内容。然而,对于超出行数限制的文本,传统的 TextView 只能通过截断或滚动的方式来处理,这限制了其在某些场景下的使用。

有鉴于此,本文将重点介绍一款功能强大的 Android 控件——可折叠TextView。它允许开发者在文本超过指定行数后,显示一个省略号和一个“全文”链接,从而让用户可以轻松展开或收起文本内容。这种特性在微博、B站等应用中非常常见,不仅提升了用户体验,还节省了宝贵的屏幕空间。

实现原理

为了实现可折叠TextView,我们可以继承 AppCompatTextView 并重写其 onMeasure() 和 onDraw() 方法。在 onMeasure() 方法中,我们需要测量要拼接的内容(通常是“...”和“全文”)的宽度。需要注意的是,这里的测量会存在一个小问题,提示内容会紧跟在原始文本之后,而不是出现在 TextView 的边界上。我们可以使用 Canvas.clipRect() 方法来解决这个问题。

在 onDraw() 方法中,我们可以绘制原始文本内容。如果文本超过了指定行数,则在最后一行末尾绘制省略号,并在其后面绘制“全文”链接。当用户点击“全文”链接时,我们可以通过设置 TextView 的 maxLines 属性为 Integer.MAX_VALUE 来展开文本内容,此时省略号和“全文”链接将消失。收起文本内容的操作与之类似,只需将 maxLines 属性重置为指定的行数即可。

实际应用

可折叠TextView 在实际应用中具有广泛的用途,以下列举几个示例:

  • 微博评论: 微博的评论区中,经常会出现过长的评论。使用可折叠TextView,用户可以快速预览评论的内容,点击“全文”链接后再展开阅读,避免了长文带来的视觉疲劳。
  • 新闻摘要: 新闻应用中,通常会显示新闻摘要。对于较长的新闻摘要,我们可以使用可折叠TextView 来控制摘要的显示长度,让用户先了解新闻的大致内容,再决定是否展开阅读全文。
  • 商品 电商应用中,商品往往包含大量的信息。我们可以使用可折叠TextView 来控制商品的显示长度,避免给用户造成信息过载的感觉。

代码示例

public class FoldableTextView extends AppCompatTextView {

    private static final int DEFAULT_MAX_LINES = 3;
    private int maxLines = DEFAULT_MAX_LINES;
    private String fullText;
    private boolean isFolded = true;

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

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

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

    private void init() {
        setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                toggleFold();
            }
        });
    }

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

        // 测量要拼接的内容的宽度
        Paint paint = getPaint();
        String ellipsis = "...";
        String fullText = getText().toString();
        float ellipsisWidth = paint.measureText(ellipsis);
        float fullTextWidth = paint.measureText(fullText);

        // 计算最大行数
        int maxLines = this.maxLines;
        int lineHeight = getLineHeight();
        int height = getMeasuredHeight();
        if (height > maxLines * lineHeight) {
            maxLines--;
        }

        // 如果文本超过了最大行数,则显示省略号和"全文"链接
        if (fullTextWidth > getMeasuredWidth()) {
            this.fullText = fullText;
            setMaxLines(maxLines);
            append(ellipsis + "全文");
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        // 绘制省略号和"全文"链接
        if (isFolded) {
            Paint paint = getPaint();
            String ellipsis = "...";
            String fullText = getText().toString();
            float ellipsisWidth = paint.measureText(ellipsis);
            float fullTextWidth = paint.measureText(fullText);
            if (fullTextWidth > getMeasuredWidth()) {
                canvas.save();
                canvas.clipRect(getMeasuredWidth() - ellipsisWidth, 0, getMeasuredWidth(), getMeasuredHeight());
                canvas.drawText(ellipsis, getMeasuredWidth() - ellipsisWidth, getLineBounds(getLineCount() - 1, null)[1], paint);
                canvas.restore();
            }
        }
    }

    public void toggleFold() {
        isFolded = !isFolded;
        if (isFolded) {
            setMaxLines(maxLines);
            append("全文");
        } else {
            setMaxLines(Integer.MAX_VALUE);
            setText(fullText);
        }
    }

    public void setMaxLines(int maxLines) {
        this.maxLines = maxLines;
        super.setMaxLines(maxLines);
    }
}

结语

可折叠TextView 是一种非常有用的 Android 控件,它可以帮助开发者解决文本内容超出行数限制的问题,同时提升用户体验和节省屏幕空间。通过本文提供的实现原理和代码示例,开发者可以轻松地将可折叠TextView集成到自己的应用中。随着 Android 技术的不断发展,相信可折叠TextView 将在更多应用场景中发挥其作用,为用户带来更加便捷和个性化的交互体验。