Tuesday, January 24, 2012

GridLayout Child View Clipping Issues

After back-porting GridLayout to 1.5+, I finally feel comfortable using it in my apps.  There's a bit of an initial learning curve, but I think that is mostly a function of un-learning the LinearLayout/RelativeLayout state of mind.  I've converted a number of my own layouts to use GridLayout and found them to be much faster/easier to understand afterwards.

There was one particular issue that I ran into that is worth noting, for its solution was not immediately obvious.  I was making a two-column GridLayout, where an image was on the left and text was on the right.  Here's a simplified version of this layout:
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >

    <Space android:layout_width="100dp" />

    <TextView android:text="@string/two_cities" />

</GridLayout>

The two Views would align next to each other nicely, but the TextView on the right would end up overflowing off the edge (the example below is not cropped - this is how it appears on the device):



What was happening was that the TextView would take up the entire width of the GridLayout, instead of taking up just the width of the cell (as I expected).


It turns out the solution is to set the width of the TextView to zero, then let the View fill its space dynamically using layout_gravity:

<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >

    <Space android:layout_width="100dp" />

    <TextView
        android:layout_width="0dip"
        android:layout_gravity="fill_horizontal"
        android:text="@string/two_cities" />

</GridLayout>

Now the problem is solved:



You need both of the highlighted attributes above; one or the other won't fix the problem.  However, it will nicely solve the issue and should be kept in mind anytime you setup a GridLayout child to fill horizontally or vertically.

13 comments:

  1. I was missing the android:layout_width="0dp". Not sure why that is necessary, but it certainly worked well.

    ReplyDelete
    Replies
    1. I believe the reason this is necessary is because the rendering happens in two steps:

      1. Determine the width of the view based on layout_width.

      2. Adjust the width based on layout_gravity.

      If the width is already set to a large size due to step #1, it won't reduce it in step #2. But if the width starts small, it will expand due to layout_gravity.

      Delete
  2. I think you meant
    app:layout_gravity="fill_horizontal"
    instead of
    android:layout_gravity="fill_horizontal"

    ReplyDelete
  3. Thank you for posting this! Just spent hours trying to figure out wtf was going on until I found this and problem solved :)

    ReplyDelete
  4. thanks a lot for this, saved me a couple of hrs.

    ReplyDelete
  5. Not a lot of working answer on internet . Thanks

    ReplyDelete
  6. Thanks for sharing this! It was super helpful.

    ReplyDelete
  7. hey, i am having an issue with this trick. If the text is in the right most cell then this works well but it doesn't work when the text is in the left most cell which I want to scale dynamically and the cell on the right is fixed.

    ReplyDelete
  8. Ditto to what others have said - this was SUPER helpful. Been pulling my hair out trying to figure out why and you solved it for me. Thanks SO much!!!

    ReplyDelete
  9. Omg, thank you so much. Have been struggled with this for all day :'(

    ReplyDelete
  10. You are a real scholar, sir. Thank you so much.

    ReplyDelete