9

My question might be, "How does one create a single-line horizontal LinearLayout with two single-line non-wrapping TextViews, where the left TextView always occupies 1/3 of the available screen width, the right TextView always occupies 2/3 of the available screen width, and the text labels truncate with ... when they are too long to display?" (If that question is clear enough and the reader -- that's you -- already has in mind a solution they are willing to share, further reading of the problem and question description may be unnecessary.)

A ListView populated with four such LinearLayouts would then look something like this:

medium length text ---- short text
short text         ---- text that is too loooooooooooooo...
loooooooooooooo... ---- short text
loooooooooooooo... ---- text that is too loooooooooooooo...
In this mock-up, in the first row, the left and right text labels were short enough to display completely, in the second row, the left label was short enough to display completely, while the text of the right label was too long and was thus truncated, and the start of the text of the right label aligned vertically with the right text of the first row, visually creating a column as if this were in a TableLayout, in the third row, the text of the left label was too long and was truncated so as to vertically align with the left text of the second and first rows, and the text of the right label started vertically aligned with the right text of the second and first rows, and in the fourth row, the text of the left label was too long and thus was displayed similarly to the left text of the third row, and the text of the right label was too long and thus was displayed similarly to the right text of the second row.

From various posts on stackoverflow and other places, I gather that while using a TableLayout with an ArrayAdapter is somewhat possible, there are downsides, and it is probably not ever the right approach to take.

I've certainly tried many combinations of layout parameters, but nothing has yet come very close to the goal. I'm trying to figure out a solution that will work on many different screen sizes, so specifying specific pixel widths probably wouldn't work very well.

Perhaps the following simple code example (with screenshot) is a good starting point for the solution, and just needs some small modifications.

(The stackoverflow code formatter was freaking out about this code. So, please forgive any funky formatting.)

public class TableLayoutLikeListView extends ListActivity
{
  @Override
  public void onCreate(Bundle savedInstanceState)
  {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.list);

    List<Datum> data = new ArrayList<Datum>();
    data.add(new Datum("short", "short"));
    data.add(new Datum("short", "loooooooooooooooooooooooooooooooooooooooooonnnnnnnnnnnnnnnnnnnnnng"));
    data.add(new Datum("loooooooooooooooooooooooooooooooooooooooooonnnnnnnnnnnnnnnnnnnnnng", "short"));
    data.add(new Datum("loooooooooooooooooooooooooooooooooooooooooonnnnnnnnnnnnnnnnnnnnnng",
        "loooooooooooooooooooooooooooooooooooooooooonnnnnnnnnnnnnnnnnnnnnng"));
    setListAdapter(new MyAdapter(this, R.layout.row, data));
  }
}
class Datum
{
  String left, right;

  Datum(String left, String right)
  {
    this.left = left;
    this.right = right;
  }
}

class MyAdapter extends ArrayAdapter<Datum>
{
  List<Datum> data;
  int textViewResourceId;

  MyAdapter(Context context, int textViewResourceId, List<Datum> data)
  {
    super(context, textViewResourceId, data);
    this.data = data;
    this.textViewResourceId = textViewResourceId;
  }

  @Override
  public View getView(int position, View convertView, ViewGroup parent)
  {
    if (convertView == null)
    {
      LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
      convertView = inflater.inflate(textViewResourceId, null);
    }
    Datum datum = data.get(position);
    if (datum != null)
    {
      TextView leftView = (TextView) convertView.findViewById(R.id.left);
      TextView rightView = (TextView) convertView.findViewById(R.id.right);
      if (leftView != null)
      {
        leftView.setText(datum.left);
      }
      if (rightView != null)
      {
        rightView.setText(datum.right);
      }
    }
    return convertView;
  }
}

list.xml: 
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">
    <ListView
        android:id="@+id/android:list"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>
row.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:weightSum="3">
    <TextView
        android:id="@+id/left"
        android:layout_width="0dip"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:singleLine="true" />
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="----" />
    <TextView
        android:id="@+id/right"
        android:layout_width="0dip"
        android:layout_height="wrap_content"
        android:layout_weight="2"
        android:singleLine="true" />
</LinearLayout>

(Note that while TextView does have the ellipsize attribute, it doesn't appear necessary to alter, as setting singleLine to true truncates and ellipsizes the labels already. I may be wrong about this.)

Following is a screenshot of this code in action:

Any advice is of course appreciated.

Thane Anthem
  • 4,093
  • 4
  • 26
  • 24

4 Answers4

6

I think this tutorial will help you. Try this..

Your row.xml should look like :

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content"
android:gravity="left|center"
android:layout_width="wrap_content"
android:paddingBottom="10px"
android:paddingTop="10px"
android:paddingLeft="3px">
 <TextView
    android:id="@+id/TextView01"
    android:layout_width="70dip"
    android:layout_height="wrap_content"
    android:gravity="left"
    android:singleLine="true"
    android:textSize="15dip"
    android:textStyle="bold"
    android:textColor="#d08021"
    android:paddingLeft="20dip">
 </TextView>
 <TextView

    android:id="@+id/TextView02"
    android:layout_width="200dip"
    android:layout_height="wrap_content"
    android:gravity="left"
    android:singleLine="true"
    android:layout_marginLeft="10dip"
    android:textSize="15dip"
    android:textStyle="bold"
    android:textColor="#7f0000">
 </TextView>

</LinearLayout>

You need this type of layout right ? Correct me if i am not wrong. See the output when i tried the above layout file.

Kartik Domadiya
  • 29,868
  • 19
  • 93
  • 104
  • 2
    Unless I've missed something, regarding a solution to my problem, the significant difference between this proposed solution and the code example I posted above is that the proposed solution uses explicit text view widths (even though they are defined with dips), which I said I do not want to do. Changing to use a SimpleAdapter seems insignificant. Have I missed the key difference? – Thane Anthem Apr 01 '11 at 06:49
  • Hey use this link : [TwoCol ListView](http://wowjava.wordpress.com/2011/03/26/dynamic-listview-in-android/)..Set this two attributes in TextView of two_col_row.xml file : android:layout_width="wrap_content" & android:singleLine="true" – Kartik Domadiya Apr 01 '11 at 07:17
  • 1
    Similar to the first proposed solution, isn't the only significant difference between this second proposed solution and the code example I posted above that the proposed solution explicit text view widths (even though they are defined with dips), which I said do not want to do? Have I missed the key difference? – Thane Anthem Apr 01 '11 at 07:31
  • If you will use android:layout_weight="wrap_content" and if its 1st textview is larger, it will display whole string taking full width of the screen and then ... .Other than this, it will work correctly. But this is not what you actually wanted. So i think you must use android:layout_width="ndips" according to your need. and set their layout_weight factor. – Kartik Domadiya Apr 01 '11 at 07:37
  • I think you have to set pixel width. See the second link i have posted in comments. It will surely solve your problem. Again i have posted row.xml file. You just need to edit this file only in your code nothing else. set layout_weight="1" (1/3rd portion) in first textview and layout_weight="2" (2/3rd portion) in second textview. – Kartik Domadiya Apr 01 '11 at 07:51
  • Mistakenly Deleted Comment: That's what I'm also thinking needs doing, which is also what I tried to do, as demonstrated in the original code I posted above. Any ideas for adjusting it or doing something else to get the TableLayout-Like view I'm after (of course, without setting pixel-explicit widths for the text views)? – Thane Anthem Apr 01 '11 at 20:04
  • Such and ugly color scheme and the way things are laid out doesnt make it very scale-able but kudos for the idea. Works pretty well – KBusc Jan 03 '14 at 14:52
3

You can use TableLayout and make it to behave like ListView (at least visually). Here is my answer.

Community
  • 1
  • 1
GrAnd
  • 10,141
  • 3
  • 31
  • 43
  • 1
    But does this introduce a possible memory leak (or at least memory mismanagement), for the reason mentioned in http://stackoverflow.com/questions/5039465/binding-a-tablelayout-with-a-arrayadapter ? – Thane Anthem Apr 01 '11 at 06:43
  • There is no memory leak or memory mismanagement in that code. The code just creates all table rows and inserts then into the table on table creation stage. Yes, it can be not optimal to create a lot of `TextView`s instead of recycling them as `ListView` does. And this variant can consume more memory, especially if the table contains hundreds rows. But if there are 10-20 rows only (as was in my case), the difference is not even noticeable. – GrAnd Apr 01 '11 at 07:15
  • In my application, I will have thousands of rows, though probably less than 10,000. If I cannot figure out something else, perhaps it's worth taking the time to performance test with a solution like this. – Thane Anthem Apr 01 '11 at 07:33
  • Answer accepted, since it addresses what I asked about. I haven't, however, implemented this approach in my application. Instead, I just grin and bear it with layout widths and weights. – Thane Anthem Apr 22 '11 at 21:40
3

hackbod presents another good-looking argument as to why ListViews cannot layout rows like TableViews in an answer to the question Does Android have a Table like Adapter for ListView.

Community
  • 1
  • 1
Thane Anthem
  • 4,093
  • 4
  • 26
  • 24
2

The best I can come up with is to have a row.xml that looks something like this. It's not ideal, but it will keep the rows with a fixed width, which will scale on a change of dimensions, but not based off of the text. It'll give you 80% of a Table Layout, with the benefits of a ListView.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content"
android:gravity="left|center"
android:layout_width="wrap_content"
android:paddingBottom="10px"
android:paddingTop="10px"
android:paddingLeft="3px">
 <TextView
    android:id="@+id/TextView01"
    android:layout_width="0dp"
    android:layout_weight=1
    android:layout_height="wrap_content"
    android:gravity="left"
    android:singleLine="true"
    android:textSize="15dip"
    android:textStyle="bold"
    android:textColor="#d08021"
    android:paddingLeft="20dip">
 </TextView>
 <TextView

    android:id="@+id/TextView02"
    android:layout_width="0dp"
    android:layout_weight=3
    android:layout_height="wrap_content"
    android:gravity="left"
    android:singleLine="true"
    android:layout_marginLeft="10dip"
    android:textSize="15dip"
    android:textStyle="bold"
    android:textColor="#7f0000">
 </TextView>

</LinearLayout>
PearsonArtPhoto
  • 38,970
  • 17
  • 111
  • 142