Search code examples
androidmeasurement

Android onMeasure() Width Value Higher Than Expected


I'm having a hard time understanding what is wrong with my onMeasure. I expect a 2x2 grid with the following layout but when I check the width and height, the height is being calculated as expected but the width is Integer.MAX_VALUE. I can't figure out what is happening to the height that isn't happening to the width. Any help in helping me figure out the correct onMeasure() method to get the expected 2x2 grid would be greatly appreciated. While the example is a 2x2 grid, I need a solution that works for any size of grid.

Following is the XML. Note that DragLayer simply extends FrameLayout. I don't believe the custom tags will cause any formatting difference but I left them in just in case.

<?xml version="1.0" encoding="utf-8"?>
<com.hogenson.dragndrop.DragLayer 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:custom="http://schemas.android.com/apk/res/com.hogenson.dragndrop"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    custom:sfen="@string/start_sfen" >

    <TableLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <com.hogenson.dragndrop.DragView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                custom:border_color="#000000"
                custom:anti_alias="true"
                custom:game_token="r" />

            <com.hogenson.dragndrop.DragView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                custom:border_color="#000000"
                custom:anti_alias="true"
                custom:game_token="p" />

        </TableRow>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <com.hogenson.dragndrop.DragView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                custom:border_color="#000000"
                custom:anti_alias="true"
                custom:game_token="K" />

            <com.hogenson.dragndrop.DragView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                custom:border_color="#000000"
                custom:anti_alias="true"
                custom:game_token="R" />

        </TableRow>

    </TableLayout>

</com.hogenson.dragndrop.DragLayer>

And here is the onMeasure() method I am trying to implement in the DragView class.

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
    int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    int heightMode = MeasureSpec.getMode(heightMeasureSpec);

    int width = MeasureSpec.getSize(widthMeasureSpec);
    int height = MeasureSpec.getSize(heightMeasureSpec);

    if (widthMode != MeasureSpec.EXACTLY)
    {
        width = Integer.MAX_VALUE;
    }

    if (heightMode != MeasureSpec.EXACTLY)
    {
        height = Integer.MAX_VALUE;
    }

    this.setMeasuredDimension(width, height);
}

Edit:

The solution Eric provided below worked perfectly for me with the addition that I needed to add layout_weight to the horizontal layouts as well, which seems to be bad programming practice.


Solution

  • Nitpick

    Could it be the fact that, in both your if statements, you're modifying width?

    if (widthMode != MeasureSpec.EXACTLY)
    {
        width = Integer.MAX_VALUE;
    }
    
    if (heightMode != MeasureSpec.EXACTLY)
    {
        width = Integer.MAX_VALUE; // Shouldn't this be height?
    }
    

    That aside...

    Before I get to my preferred solution, I'll start by suggesting that you attach android:stretchColumns="*" to your TableLayout. This will allow the columns to fill the allotted space (and not be too small).

    Using LinearLayouts instead

    However, I think what you want to accomplish is best done with LinearLayouts. Basically, this:

    <LinearLayout
        ...
        android:orientation="vertical" >
    
        <LinearLayout
            ...
            android:orientation="horizontal" >
    
            <com.hogenson.dragndrop.DragView
                android:layout_width="0px"
                android:layout_height="match_parent"
                android:layout_weight="1" />
    
            <!-- more cells for row 1 -->
    
        </LinearLayout>
    
        <LinearLayout
            ...
            android:orientation="horizontal" >
    
            <com.hogenson.dragndrop.DragView
                android:layout_width="0px"
                android:layout_height="match_parent"
                android:layout_weight="1" />
    
            <!-- more cells for row 2 -->
    
        </LinearLayout>
    
    </LinearLayout>
    

    Lastly, squares

    Finally, if you want your objects to be square (same width and height), have a look at this answer.

    Note that, with the above solutions, you're probably best not to fiddle with onMeasure in this case; the XML should be able to take care of it for you. And as always, good luck!