android 将聊天气泡宽度调整为换行文本

android resize chat bubbles width to wrapped text

我正在尝试处理文本视图中的九个补丁和自动换行。问题是 TextView 不会将其宽度调整为换行文本,因此聊天气泡留下了一个我无法减少的巨大差距。

有空隙的聊天气泡

对 ViewHierarchy 的调查表明,这些间隙位于聊天布局的视图层次结构 TextView 内部。所以跟九段没有关系。

可能有人遇到过类似的问题...

<LinearLayout
android:id="@+id/messages"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="vertical">

<TextView
    android:id="@+id/senderName"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:ellipsize="marquee"
    android:gravity="bottom|start"
    android:maxLines="1"
    android:layout_marginTop="5dp"
    android:layout_marginStart="18dp"
    android:layout_marginLeft="18dp"
    android:textColor="@color/talkatone_gray"
    android:textSize="@dimen/chat_item_meta_info_text_size"
    android:visibility="gone"/>

    <TextView
        android:id="@+id/message_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="end"
        android:layout_marginBottom="@dimen/chat_bubble_margin_top"
        android:background="@android:color/transparent"
        android:lineSpacingExtra="4sp"
        android:clickable="true"
        android:focusable="true"
        android:focusableInTouchMode="true"
        android:gravity="center_vertical"
        android:text="@string/form_chat_failed_to_open"
        android:textAppearance="?android:attr/textAppearanceSmall"
        android:textColor="@color/chat_text"
        android:textSize="@dimen/chat_text_message_size"/>

    <FrameLayout
        android:id="@+id/attachment_frame"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="@dimen/chat_bubble_margin_top"
        android:orientation="vertical">

            <ImageButton
                android:id="@+id/video_play_button"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical|center_horizontal"
                android:background="@android:color/transparent"
                android:contentDescription="@null"
                android:src="@drawable/play_gif"/>
    </FrameLayout>

使用 9 个补丁图像作为布局的背景,这样您就可以创建可自动调整大小以适应视图内容的位图图像。

很遗憾,您的问题还包括您的答案:

TextView doesn't resize its width to wrapped text

当您使用 wrap_content 并允许多行时,系统将首先尽可能地增加 TextView 的宽度,然后才开始添加换行符。它从不在最后通过传递以回收可用宽度。

当然,与所有事情一样,您可以通过编写自己的自定义来解决此问题TextView class。这是另一个试图解决类似问题的项目的 link;也许它会帮助你出主意。

其他问题:Uniform text wrapping in TextView

自定义 TextView 库:https://github.com/dziobas/UniformTextView

在你的情况下,主要问题是你在适配器中使用它来实现 viewholder 模式。

所以您需要解决两个问题:

  1. 每次重新使用之前重置 TextView 的宽度。
  2. 在您的 TextView 度量中定义最长的行并设置适当的宽度。

要重置 TextView 宽度,请将其添加到您的适配器 getView() 方法中,当您重复使用您的 holder 时,下一步:

ViewGroup.LayoutParams paramsReset = holder.messageText.getLayoutParams();
paramsReset.width = ViewGroup.LayoutParams.WRAP_CONTENT;
holder.messageText.setLayoutParams(paramsReset);

对于第二期,您需要创建自定义视图,从 TextView 扩展并覆盖 onDraw() 方法:

@Override
protected void onDraw(Canvas canvas)
{
    super.onDraw(canvas);
    if(getLineCount() > 1)
    {
        float longestLineWidth = -1;
        for (int lineIndex = 0; lineIndex < getLineCount(); lineIndex++)
        {
            int lineStartIndex = getLayout().getLineStart(lineIndex);
            int lineEndIndex = getLayout().getLineEnd(lineIndex);
            String currentTextLine = getText().toString().substring(lineStartIndex, lineEndIndex);
            // Added "_____" for your paddings.
            float currentLineWidth = getPaint().measureText(currentTextLine + "_____");

            if (longestLineWidth < currentLineWidth)
            {
               longestLineWidth = currentLineWidth;
            }
        }
        ViewGroup.LayoutParams paramsNew = getLayoutParams();
        paramsNew.width = (int) longestLineWidth;
        setLayoutParams(paramsNew);
    }
}

我覆盖了 onDraw() 也是因为需要在 ListView 中使用它,看起来你需要找到其他回调,当 holder 出现在视图中时调用。


有效,但效率不高,还有一些其他问题,请作为第一步使用。