hBrent
hBrent

Reputation: 1716

Make TextView as wide as possible without crowding out other views

I want the following layout handling in my app:

enter image description here

As you can see, the text is allowed to be as wide as it can be without pushing off the screen the other views that appear to its right, ellipsizing as necessary. There will never be more than 3 color swatches, and no fewer than 1, and all swatches and the x in the circle must always be visible. When the text is short, it should behave as seen in the last 2 rows (the ferns).

I've tried to put the text and images in a LinearLayout, but when the text is too long the images are not visible (or not entirely visible). I assume there's some way to indicate that the images should always take up as much room as they need, with the TextView taking up the rest or as much as it needs, but I can't seem to figure out how. I don't know if a RelativeLayout would work better for this, or maybe a TableLayout/TableRow or GridLayout, though nothing I've read seems to cover this situation.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">

<TextView
    android:id="@+id/plant_name"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:gravity="center_vertical"
    android:maxLines="1"
    android:singleLine="true"
    android:ellipsize="end"
    android:layout_marginRight="3dp"/>

<LinearLayout
    android:id="@+id/color_0"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginLeft="2dp"
    android:layout_marginRight="2dp">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/btn_remove_plant"
        android:visibility="invisible"/>
</LinearLayout>

<LinearLayout
    android:id="@+id/color_1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginLeft="2dp"
    android:layout_marginRight="2dp"
    android:visibility="gone">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/btn_remove_plant"
        android:visibility="invisible"/>
</LinearLayout>

<LinearLayout
    android:id="@+id/color_2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginLeft="2dp"
    android:layout_marginRight="2dp"
    android:visibility="gone">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/btn_remove_plant"
        android:visibility="invisible"/>
</LinearLayout>

<ImageView
    android:id="@+id/remove_plant"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/btn_remove_plant"
    android:layout_marginLeft="3dp"/>

</LinearLayout>

Upvotes: 8

Views: 2021

Answers (3)

CommonsWare
CommonsWare

Reputation: 1006584

When the text is short, it should behave as seen in the last 2 rows (the ferns).

I don't think that a standard layout is going to give you what you want. My guess is that you will have to create a custom ViewGroup that implements your requirements. Qberticus' implementation is probably as close as you'll get using out-of-the-box layouts.

That being said, I can't rule out GridLayout being able to pull this off, somehow.

Personally, I'd go with a TableLayout, with four columns for your color swatches and X icons, and a fifth column for the text. You could dynamically construct the table rows to have the text fill columns that are not going to be used by swatches, and you would use android:strechColums="0" to give all extra space to the left-most column where the text is based. As with Qberticus' approach, this leaves you with right-flush swatches and icons, which IMHO is a better UI.

If your concern with the right-flush swatches and icons is having gaps of whitespace between the text and the swatches/icons, make the text have right gravity (or end if you are support RTL languages).

Upvotes: 0

Rich Schuler
Rich Schuler

Reputation: 41972

Here is a working layout. Two things that are happening. One, the rows are using LinearLayout with layout_width="wrap_content". This keeps the LinearLayout from expanding beyond its content keeping everything left aligned (your bottom two examples). Two, the TextView is using android:layout_weight="1" and android:layout_width="0dp" to tell the LinearLayout that it should expand this TextView to fill the rest of the space of available but to not push out the other views (your top three examples). Note: this is not all layout_weight does, only that this is what it is doing in this context.

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

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

        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:ellipsize="end"
            android:lines="1"
            android:text="This is a long line of text and is testing something. This is a long line of text and is testing something. This is a long line of text and is testing something." />

        <View
            android:layout_width="24dp"
            android:layout_height="24dp"
            android:layout_marginLeft="4dp"
            android:layout_marginRight="4dp"
            android:background="#F00" />

        <View
            android:layout_width="24dp"
            android:layout_height="24dp"
            android:layout_marginLeft="4dp"
            android:layout_marginRight="4dp"
            android:background="#0F0" />

        <View
            android:layout_width="24dp"
            android:layout_height="24dp"
            android:layout_marginLeft="4dp"
            android:layout_marginRight="4dp"
            android:background="#00F" />

        <Button
            android:layout_width="24dp"
            android:layout_height="24dp"
            android:layout_marginLeft="4dp"
            android:layout_marginRight="4dp" />
    </LinearLayout>

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

        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:ellipsize="end"
            android:lines="1"
            android:text="This is a long line of text and is testing something. This is a long line of text and is testing something. This is a long line of text and is testing something." />

        <View
            android:layout_width="24dp"
            android:layout_height="24dp"
            android:layout_marginLeft="4dp"
            android:layout_marginRight="4dp"
            android:background="#F00" />

        <View
            android:layout_width="24dp"
            android:layout_height="24dp"
            android:layout_marginLeft="4dp"
            android:layout_marginRight="4dp"
            android:background="#0F0" />

        <Button
            android:layout_width="24dp"
            android:layout_height="24dp"
            android:layout_marginLeft="4dp"
            android:layout_marginRight="4dp" />
    </LinearLayout>


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

        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:ellipsize="end"
            android:lines="1"
            android:text="This is some line of text." />

        <View
            android:layout_width="24dp"
            android:layout_height="24dp"
            android:layout_marginLeft="4dp"
            android:layout_marginRight="4dp"
            android:background="#F00" />

        <View
            android:layout_width="24dp"
            android:layout_height="24dp"
            android:layout_marginLeft="4dp"
            android:layout_marginRight="4dp"
            android:background="#00F" />

        <Button
            android:layout_width="24dp"
            android:layout_height="24dp"
            android:layout_marginLeft="4dp"
            android:layout_marginRight="4dp" />
    </LinearLayout>

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

        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:ellipsize="end"
            android:lines="1"
            android:text="This is short" />

        <View
            android:layout_width="24dp"
            android:layout_height="24dp"
            android:layout_marginLeft="4dp"
            android:layout_marginRight="4dp"
            android:background="#F00" />

        <Button
            android:layout_width="24dp"
            android:layout_height="24dp"
            android:layout_marginLeft="4dp"
            android:layout_marginRight="4dp" />
    </LinearLayout>

</LinearLayout>

Upvotes: 8

Anonymous
Anonymous

Reputation: 4900

This code gives you the screen size in dp and pixels. Set your images at a fixed size that you like, for example 30dp or Math.min(screenWidth,screenHeight)/100 to set it relative to the display size. After that, since you know how many images will be shown substruct the (number of images) * imageSize from the tottal screenWidth and set this as the textview width

WindowManager wm2 = (WindowManager) con.getSystemService(Context.WINDOW_SERVICE);
Display display = wm2.getDefaultDisplay();
DisplayMetrics outMetrics = new DisplayMetrics ();   display.getMetrics(outMetrics);
float density  = getResources().getDisplayMetrics().density;
dpHeight  = (int) (outMetrics.heightPixels / density); 
dpWidth  = (int) (outMetrics.widthPixels / density);
screenWidth=outMetrics.widthPixels; 
screenHeight=outMetrics.heightPixels;

this is how you set the textview's width programmatically

LinearLayout.LayoutParams params=(LinearLayout.LayoutParams)textView.getLayoutParams();
params.width=/calculated size/; 
textView.setLayoutParams(params);

Upvotes: 0

Related Questions