Reputation: 186
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
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
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 items)"
Note:
Here, ' ' is character code of 'SPACE'. This bind's your string as one
String and stays together.
Hope this resolves your problem.
Upvotes: 0
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
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
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 TextView
s, 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