2 TextViews, left with ellipsis, right with nowrap, single line
Asked Answered
F

4

4

It's the first time I post on this forum, hope it's gonna be fine :)

I'm developping an Android App for public transportation in my city.

Here is what I have

[ |short destination   ||next departure| ]
[ |way too long dest...||next departure| ]

Here is what I want:

[ |short destination||next departure|    ]
[ |way too long dest...||next departure| ]

Here is a more complete example: s28.postimg.org/5gejnvfd9/actual2.png

Weird coloured backgrounds are just here to easily identify layouts/textviews. You can also ignore the brown line (which is ok).

Basically, I want to have the destination [red background] which have a variable length, and on its right, I want the first departure time [green background]. Everything on one line.

I need to always have the first departure information fully displayed (nowrap). The destination could be wrapped with an ellipsis (...). [Optional question, how to replace the ellipsis '...' with '.' ?]

Here is the best working code I have so far:

    <RelativeLayout 
        android:layout_width="fill_parent"
        android:layout_height="wrap_content">

        <TextView
            android:id="@+id/txtTitleDestination"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_toLeftOf="@+id/txtTitleFirstDeparture"
            android:background="#FF0000"
            android:ellipsize="end"
            android:maxLines="1"
            android:padding="0dp"
            android:scrollHorizontally="true"
            android:textSize="18sp"
            android:textStyle="bold" />

        <TextView
            android:id="@+id/txtTitleFirstDeparture"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="0dp"
            android:layout_marginRight="0dp"
            android:layout_alignParentRight="true"
            android:background="#00FF00"
            android:ellipsize="none"
            android:maxLines="1"
            android:padding="0dp"
            android:textSize="18sp"
            android:textStyle="bold" 
            />

    </RelativeLayout>

I've tried TableLayout and LinearLayour instead of the RelativeLayout, but with no success :(

Any idea how I could do that?

Thanks in advance!

Louloox

[SOLVED] Just have to lightly modify the valbertos answer:

titleDestination.post(new Runnable() {
        @Override
        public void run() {             
            int widthTextViewDeparture = measureTextWidthTextView(titleFirstTime, pContext);
            int widthTextViewDestination = titleDestination.getWidth();
            int widthTextViewParent = rl_parent.getWidth();
            if(widthTextViewDestination + widthTextViewDeparture > widthTextViewParent) {
                titleDestination.setWidth(widthTextViewParent - widthTextViewDeparture);
                titleDestination.setEllipsize(TruncateAt.END);
                titleDestination.setHorizontallyScrolling(true);
            }
        }
    });

Setting the Ellipsis only if necessary makes the text properly truncated.

Before: 
Lingolsheim Thiergaten --> Lingolsheim...     [1'23"] 21h23

With the modification:
Lingolsheim Thiergaten --> Lingolsheim Thi... [1'23"] 21h23

Thanks again :)

Foliose answered 6/9, 2014 at 15:30 Comment(2)
Here is a more complete example : s28.postimg.org/5gejnvfd9/actual2.pngFoliose
What you have to understant is that, the content is dynamically retrieve from a WebService. Thus, I don't know in adavance how large is the destination name, so I definitely need to have the "Destination name" TextView dynamic (in terms of width), and I don't want this one to "hide" the right TextView.Foliose
G
1

To do what you are asking for, you must adjust the width of the first view dynamically based on the text width of the second view.

//Code

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.test);

    final TextView tv_1 = (TextView) findViewById(R.id.tv_1);
    tv_1.post(new Runnable() {
        @Override
        public void run() {
            View rl_parent = findViewById(R.id.rl_parent);
            TextView tv_2 = (TextView) findViewById(R.id.tv_2);
            int widthTextView2 = measureTextWidthTextView(tv_2);
            if(tv_1.getWidth() + widthTextView2 > rl_parent.getWidth()) {
                tv_1.setWidth(tv_1.getWidth() - widthTextView2);
            }
        }
    });
}

private int measureTextWidthTextView(TextView textView) {
    int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(getScreenWidth(), View.MeasureSpec.AT_MOST);
    int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
    textView.measure(widthMeasureSpec, heightMeasureSpec);
    return textView.getMeasuredWidth();
}

private int getScreenWidth() {
    WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
    Display display = wm.getDefaultDisplay();
    Point size = new Point();
    display.getSize(size);
    return size.x;
}

//Layout

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="300dp"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <RelativeLayout
        android:id="@+id/rl_parent"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:background="#348D63">

        <TextView
            android:id="@+id/tv_1"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:background="#BD160B"
            android:gravity="center_vertical"
            android:maxLines="1"
            android:paddingLeft="10dp"
            android:paddingRight="10dp"
            android:text="Elsau Elsau Elsau Elsau Elsau Elsau Elsau"
            android:textStyle="bold" />

        <TextView
            android:id="@+id/tv_2"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_toRightOf="@+id/tv_1"
            android:gravity="center_vertical"
            android:minWidth="50dp"
            android:paddingLeft="10dp"
            android:paddingRight="10dp"
            android:text="[11:30 14:23]"
            android:textStyle="bold" />

    </RelativeLayout>

    <!-- Rest of the layout -->

</LinearLayout>

Use android:maxLines="1" instead of android:singleLine="true" to get rid off the ugly dots -as I did in my example.

Also, I recommend you to use include for the "time" section, instead of repeating the TextViews twice. I’ve just done it like that to keep simple the example.

Glutinous answered 6/9, 2014 at 16:6 Comment(5)
Hi valbertos, Thank you, but I tried both RelativeLayout your proposed, but the first one doesn't let the right TextView visible if the left TextView is too long. The second RelativeLayout has a fixed width for the left TextView, which is not ok since it has a dynamic size.Foliose
I didn't understand you well. Try again, I've modified my question ;)Amalgamation
Well, actually it seems you understood what I meant :) I want to resize the width of the left TextView according to the right one, so that the right is always fully-displayed on 1 line. But I thought I could do that from the xml View. I'll try your solution soon :) Thanks.Foliose
Yes, it's working :) Thanks a lot! Any idea if it's do-able directly with the xml View ? I have the feeling that it can be done in HTML/css (1 table, 2 columns, 1st ellipsis, 2nd nowrap). Anyway, thanks a lot! Great forum =) Cheers!Foliose
You're welcome! I don't think it could be achieved just from layout because the layout system doesn't support such complex calculations. :)Amalgamation
F
5

You don't need do it programmatically, ConstraintLayout is a magic!

Just use this code

app:layout_constraintHorizontal_bias="0" align view left

app:layout_constrainedWidth="true" to wrap left text

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="8dp">

    <TextView
        android:id="@+id/leftText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:ellipsize="end"
        android:maxLines="1"
        app:layout_constrainedWidth="true"
        app:layout_constraintHorizontal_bias="0"
        app:layout_constraintEnd_toStartOf="@id/rightText"
        app:layout_constraintHorizontal_chainStyle="packed"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="|short destination|" />

    <TextView
        android:id="@+id/rightText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/leftText"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="|next departure|" />

</androidx.constraintlayout.widget.ConstraintLayout>

Here is result

enter image description here enter image description here

Frimaire answered 22/10, 2019 at 4:55 Comment(0)
S
4

I found a way to do it using Linear Layout, the trick is not to forget width="wrap_content" for the linearLayout, hope it can help.

<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal">


<TextView
    android:layout_width="0dip"
    android:layout_height="wrap_content"
    android:layout_weight="1"
    android:ellipsize="end"
    android:singleLine="true" />

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:singleLine="true" />

Sikes answered 17/6, 2015 at 21:3 Comment(0)
G
1

To do what you are asking for, you must adjust the width of the first view dynamically based on the text width of the second view.

//Code

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.test);

    final TextView tv_1 = (TextView) findViewById(R.id.tv_1);
    tv_1.post(new Runnable() {
        @Override
        public void run() {
            View rl_parent = findViewById(R.id.rl_parent);
            TextView tv_2 = (TextView) findViewById(R.id.tv_2);
            int widthTextView2 = measureTextWidthTextView(tv_2);
            if(tv_1.getWidth() + widthTextView2 > rl_parent.getWidth()) {
                tv_1.setWidth(tv_1.getWidth() - widthTextView2);
            }
        }
    });
}

private int measureTextWidthTextView(TextView textView) {
    int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(getScreenWidth(), View.MeasureSpec.AT_MOST);
    int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
    textView.measure(widthMeasureSpec, heightMeasureSpec);
    return textView.getMeasuredWidth();
}

private int getScreenWidth() {
    WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
    Display display = wm.getDefaultDisplay();
    Point size = new Point();
    display.getSize(size);
    return size.x;
}

//Layout

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="300dp"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <RelativeLayout
        android:id="@+id/rl_parent"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:background="#348D63">

        <TextView
            android:id="@+id/tv_1"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:background="#BD160B"
            android:gravity="center_vertical"
            android:maxLines="1"
            android:paddingLeft="10dp"
            android:paddingRight="10dp"
            android:text="Elsau Elsau Elsau Elsau Elsau Elsau Elsau"
            android:textStyle="bold" />

        <TextView
            android:id="@+id/tv_2"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_toRightOf="@+id/tv_1"
            android:gravity="center_vertical"
            android:minWidth="50dp"
            android:paddingLeft="10dp"
            android:paddingRight="10dp"
            android:text="[11:30 14:23]"
            android:textStyle="bold" />

    </RelativeLayout>

    <!-- Rest of the layout -->

</LinearLayout>

Use android:maxLines="1" instead of android:singleLine="true" to get rid off the ugly dots -as I did in my example.

Also, I recommend you to use include for the "time" section, instead of repeating the TextViews twice. I’ve just done it like that to keep simple the example.

Glutinous answered 6/9, 2014 at 16:6 Comment(5)
Hi valbertos, Thank you, but I tried both RelativeLayout your proposed, but the first one doesn't let the right TextView visible if the left TextView is too long. The second RelativeLayout has a fixed width for the left TextView, which is not ok since it has a dynamic size.Foliose
I didn't understand you well. Try again, I've modified my question ;)Amalgamation
Well, actually it seems you understood what I meant :) I want to resize the width of the left TextView according to the right one, so that the right is always fully-displayed on 1 line. But I thought I could do that from the xml View. I'll try your solution soon :) Thanks.Foliose
Yes, it's working :) Thanks a lot! Any idea if it's do-able directly with the xml View ? I have the feeling that it can be done in HTML/css (1 table, 2 columns, 1st ellipsis, 2nd nowrap). Anyway, thanks a lot! Great forum =) Cheers!Foliose
You're welcome! I don't think it could be achieved just from layout because the layout system doesn't support such complex calculations. :)Amalgamation
D
0

Maybe you should use a LinearLayout instead of RelativeLayout and use the layout_weight attribute.

<LinearLayout android:orientation="horizontal" ...>
    <TextView android:id="@+id/txtTitleDestination" android:layout_width="wrap_content" ... />
    <TextView android:id="@+id/txtTitleFirstDeparture" android:layout_width="0dp" android:layout_weight="1" ... />
</LinearLayout>
Desirous answered 6/9, 2014 at 15:40 Comment(1)
Hi pomber, Well, thank you, it was also my first idea, but it's not working: if the left TextView is too long, the right one is not visible...Foliose

© 2022 - 2024 — McMap. All rights reserved.