gnunaes
gnunaes

Reputation: 186

Wrapping a block of text if the line that textView sits on gets too long

I'm looking for the best way to meet this requirement. I apologize if it's been answered elsewhere, I can't find a solution to what seems like an easy problem.

You have a line of text in a list that looks something like this:

Title of the item - (5 items)

If the title of the item gets to be too long, then it wraps, which is expected. However, it shouldn't wrap between the "5" and the "items". If it needs to wrap, then the whole "(5 items)" should wrap to the next line. And the text of the title should ellipse.

I can't seem to find a way to create a layout that will work for this.

Upvotes: 3

Views: 3820

Answers (4)

Renato Probst
Renato Probst

Reputation: 6054

Have you tried a relative layout with two textViews, one for title and other for "label" ? Use Relative layout to left of:

<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/container" >

<TextView android:id="@+id/text1"
    android:text="a very very very long title"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:toLeftOf="@+id/label" />


<TextView android:id="@+id/label"
    android:text="(5 items)"
    android:singleLine="true"
    android:layout_alignParentRight="true" 
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

You can use linearLayout weight too this will make the text always fit to a proportion (80% for title, and 20% for label in this example):

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:weight_sum="100"
android:orientation="horizontal"
android:id="@+id/container" >

<TextView android:id="@+id/text1"
    android:weight="80"
    android:text="a very very very long title"
    android:layout_width="0dp"
    android:layout_height="wrap_content" />


<TextView android:id="@+id/label"
    android:text="(5 items)"
    android:singleLine="true"
    android:weight="20"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

</LinearLayout>

Upvotes: 0

A.R.
A.R.

Reputation: 2641

What i can understand from your question is that

1) It does not matter how long the title text is,it can wrap according to its length.

2) Your text "(5 items)" should not break, it should stays together. What ever
   is the length of your TITLE.

If above 2 points are correct.Then the simple solution is this

 Just replace your String "(5 items)"

with

 String "(5&#160;items)"

Note:

Here, '&#160' is character code of 'SPACE'. This bind's your string as one 
String and stays together.

Hope this resolves your problem.

Upvotes: 0

Dhir Pratap
Dhir Pratap

Reputation: 1188

The TextUtils classs has as method called ellipsize

public static CharSequence ellipsize (CharSequence text, TextPaint p, float avail, TextUtils.TruncateAt where) Added in API level 1

Returns the original text if it fits in the specified width given the properties of the specified Paint, or, if it does not fit, a truncated copy with ellipsis character added at the specified edge or center.

Here is how we can use it. Lets assume "Title of the item - (5 items)" is fullText, (5 items) is suffix, textView is your text view containing the text.

String ellipsizedText = TextUtils.ellipsize(fullText, textView.getPaint(), fullTexViewtWidth ,TextUtils.TruncateAt.END);

Now either the text will be ellipsized or it won't. We can check this by checking for the presence of suffix in the ellipsizedText. If it is ellipsized (suffix is removed), we should call the ellipsize function again but this time with reduced width since we want to preserve a space for our suffix string and remove suffix since we are adding it separately. So, the new call will be

ellipsizedText = TextUtils.ellipsize(removedSuffixText, textView.getPaint(), reducedWidth ,TextUtils.TruncateAt.END);

finally we set the text of the textView as ellipsizedText+suffix;

Few values we need to find out

  1. fullTexViewtWidth - This can be tricky since we have not specified specific width for the text view. suppose we set the width as match parent then we can achieve it via view tree observer. Follow the answers here
  2. reducedWidth - This is even more tricky. To calculate this we need to find the width occupied by suffix and subtract it from fullTexViewtWidth. This answer explains how to find width occupied by suffix

    final float densityMultiplier = getContext().getResources().getDisplayMetrics().density; final float scaledPx = 20 * densityMultiplier; paint.setTextSize(scaledPx); final float size = paint.measureText("sample text");

I am afraid this will only work when maxLines is 1 and width is set to matchparent for textView.

Upvotes: 1

natario
natario

Reputation: 25194

This may help. You can define which part of the text is going to be truncated by using the android:ellipsize attribute.

In your case, as per the linked answer, I would use android:ellipsize="middle" or android:ellipsize="marquee", which makes the text slide to be read.

While this does not actually answers your requirements (number of items automatically going to line two) I think it might be a better solution.

See official info here.


The other thing that comes to my mind is using two different TextViews, one for title and another one (right-aligned?) for item counts. I would give android:ellipsize="end" to the first and android:layout_width="wrap_content" to the latter.


Also you could go for a count TextView below the title, that gets appended to the title if there's enough room.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/container"
    android:orientation="vertical" >

    <TextView android:id="@+id/text1"
        android:text="a very very very long title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:ellipsize="end" />


    <TextView android:id="@+id/text2"
        android:text="(5 items)"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

And in your code you can check for width:

View container = findViewById(R.id.container);
TextView tv1 = (TextView) findViewById(R.id.text1);
TextView tv2 = (TextView) findViewById(R.id.text2);


String HEADER = tv1.getText();
String COUNT = tv2.getText();

int widthHeader = tv1.getWidth();
int widthCount = tv1.getWidth();
int widthAvailable = container.getWidth();

if (widthAvailable - widthHeader > widthCount) {
    tv1.setText(HEADER + " - " + COUNT);
    tv2.setText("");
}

Upvotes: 1

Related Questions