简体   繁体   中英

android resize chat bubbles width to wrapped text

I'm trying to deal with nine patches and word wrapping inside a text view. The problem is that TextView doesn't resize its width to wrapped text, so the chat bubbles left a huge gap which I cannot reduce.

chat bubbles with gaps

图片

Investigation of ViewHierarchy shows that these gaps are inside the TextView, view hierarchy of chat layout. so it's not related to the nine-patch. 图片

May be somebody faced a similar issue...

<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个补丁图像作为布局的背景,这样您就可以创建位图图像,该位图图像会自动调整大小以容纳视图的内容。

Unfortunately, your question also includes your answer:

TextView doesn't resize its width to wrapped text

When you use wrap_content and allow multiple lines, the system will first grow the width of the TextView as wide as it can and only then start adding linebreaks. It never does a pass at the end to reclaim available width.

Of course, as with all things, you can solve this problem by writing your own custom TextView class. Here's a link to another project that attempted to solve a similar problem; maybe it will help give you ideas.

Other question: Uniform text wrapping in TextView

Custom TextView lib: https://github.com/dziobas/UniformTextView

in your case the main problem is that you use it in adapter with viewholder pattern implementation.

So there is two issues you need to solve:

  1. Reset TextView width each time before you'll reuse it.
  2. Define longest line in your TextView measure and set appropriate width.

For reset TextView width add to your adapter getView() method, when you reuse your holder, next:

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

For second issue you need to create custom view, extended from TextView and override onDraw() method:

@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);
    }
}

I override onDraw() also because of needed for use it in ListView, looks like you'll need to find other callback, that calls when holder has appeared in view.


It works, but not efficient, and have some other issues, please use it as first step.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM