Sunday 24 January 2010

How does TableLayout handle column overflow

Tell me...
In case of an overflow, TableLayout uses the following simple formula to reduce the width of the columns such that all columns are visible to the user (most of the time)
r=(g-w)/n
  • r= The amount (in pixels) by which the shrinkable columns must be reduced.
  • g= The sum of a widths and paddings of all columns
  • w=The maximum width of the table (constrained by its parent)
  • n=The number of shrinkable columns in the shrinkColumn attribute

On close review of the above, a few things jump out:

What is ShrinkColumns attribute?
This attribute is a comma separated values of column indexes (starting at 0) that should be narrowed in case of an overflow. All other columns are not touched to handle the overflow condition.
Show me...
I have two very wide cells, TextView01 and TextView04, which will trigger the overflow handling logic in TableLayout. I chose columns 0 and 1 (i.e both) to be shrinkable.
  1. <TableLayout android:shrinkColumns="0,1" android:id="@+id/TableLayout01" android:layout_width="wrap_content" android:layout_height="wrap_content">
    1. <TableRow android:id="@+id/TableRow01" >
      1. <TextView android:id="@+id/TextView01" android:text="Exploring andoring is fun. Let's keep going for some more time."></TextView>
      2. <TextView android:id="@+id/TextView02" android:text="Go for it"></TextView>
      3. </TableRow>
    2. <TableRow android:id="@+id/TableRow01">
      1. <TextView android:id="@+id/TextView03" android:text="Hello"></TextView>
      2. <TextView android:id="@+id/TextView04" android:text="There are seven days in a week."></TextView>
      </TableRow>
    </TableLayout>

You can see both columns have been fit into the available width. Also, think about the resultant width distribution. We it visit again in the next section.

Descendant views can help too!
As we noted earlier, it could be good idea (and it is) to limit the overflow in the first place. Sometimes, this could be done by making some simple design changes to the views in the table layout. In this example, I have added "layout_width=wrap_content" attribute to the the text views. They are less demanding than the counterparts in the previous example, thus causing lesser overflow.
  1. <TableLayout android:shrinkColumns="0,1" android:id="@+id/TableLayout01" android:layout_width="wrap_content" android:layout_height="wrap_content" >
    1. <TableRow android:id="@+id/TableRow01">
      1. <TextView android:layout_width="wrap_content" android:id="@+id/TextView01" android:text="Exploring andoring is fun. Let's keep going for some more time."></TextView>
      2. <TextView android:layout_width="wrap_content" android:id="@+id/TextView02" android:text="Go for it"></TextView>
      </TableRow>
    2. <TableRow android:id="@+id/TableRow01">
      1. <TextView android:layout_width="wrap_content" android:id="@+id/TextView03" android:text="Hello"></TextView>
      2. <TextView android:layout_width="wrap_content" android:id="@+id/TextView04" android:text="There are seven days in a week."></TextView>
      </TableRow>
    </TableLayout>

Notice, the difference! The columns seem to have a better balance and are closer to their natural size. Of course, whether this desired or not is matter of design choice.

Issue with one size fits all approach

As we noted earlier, all shirnkable columns are reduced by the same amount. And neither is the columns' initial width taken into consideration. Sometimes bad things can happen due this "one size fits all" approach. In the exmaple below, the second column's width is much smaller than the overflow caused by the first column.

  1. <TableLayout android:shrinkColumns="0,1" android:id="@+id/TableLayout01" android:layout_width="wrap_content" android:layout_height="wrap_content" >
    1. <TableRow android:id="@+id/TableRow01">
      1. <TextView android:id="@+id/TextView01" android:text="Exploring andoring is fun. Let's keep going for some more time."></TextView>
      2. <TextView android:id="@+id/TextView02" android:text="H"></TextView>
      </TableRow>
    2. <TableRow android:id="@+id/TableRow01">
      1. <TextView android:id="@+id/TextView03" android:text="Hello"></TextView>
      2. <TextView android:id="@+id/TextView04" android:text="2"></TextView>
      </TableRow>
    </TableLayout>

Notice how ugly it looks? Not only is column # 2 missing, also the wrapping is all messed up.

Looking up the widgets in the heirarchy viewer (below) gives us comfort that all widgets exist, its just that the redering that has gone kaput. Based on this observation, in my opinion shrinkColumns should be a collection of relatively equal columns.

Remind me again, why is shrinkColumn important?

Just to wrap up this column, let's see what happen when we drop the "shinkColumns" attribute?

  1. <TableLayout android:shrinkColumns="0,1" android:id="@+id/TableLayout01" android:layout_width="wrap_content" android:layout_height="wrap_content">
    1. <TableRow android:id="@+id/TableRow01" >
      1. <TextView android:id="@+id/TextView01" android:text="Exploring andoring is fun. Let's keep going for some more time."></TextView>
      2. <TextView android:id="@+id/TextView02" android:text="Go for it"></TextView>
      3. </TableRow>
    2. <TableRow android:id="@+id/TableRow01">
      1. <TextView android:id="@+id/TextView03" android:text="Hello"></TextView>
      2. <TextView android:id="@+id/TextView04" android:text="There are seven days in a week."></TextView>
      </TableRow>
    </TableLayout>

Because there the TableLayout cannot determine which columns to shrink, it leaves all columns untouched. The result is that column # 2 is pushed out of the viewport.

Once again, the heirarchy viewer confirm that all the text views exist.

1 comment:

  1. I have been dealing with this issue for a while and completely missed that shrinkColumns would solve it. Thank you so much for taking the time to write this.

    ReplyDelete

Blog Archive

Followers