Why is my android custom view not square?

Subclass ImageView and override onMeasure and pass to

super.onMeasure(widthMeasureSpec, widthMeasureSpec);

the whole class:

public class SquaredImageView extends ImageView {

        public SquaredImageView(Context context) {
                super(context);
        }

        public SquaredImageView(Context context, AttributeSet attrs) {
                super(context, attrs);
        }

        public SquaredImageView(Context context, AttributeSet attrs, int defStyle) {
                super(context, attrs, defStyle);
        }

        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
                super.onMeasure(widthMeasureSpec, widthMeasureSpec);
        }

}

Edit: I tried with a normal view

public class CustomView extends View {

    public CustomView(Context context) {
        super(context);
        setBackgroundColor(Color.RED);
    }

    public CustomView(Context context, AttributeSet attrs) {
        super(context, attrs);

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
                super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    int width = getMeasuredWidth();
    int heigth = getMeasuredHeight();

    int dimen = (width > heigth) ? heigth : width;

    setMeasuredDimension(dimen, dimen);
    }
}

and a TestActivity

public class TestActivity extends Activity {

    protected void onCreate(android.os.Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new CustomView(this));
    }

}

it draws a squared red rectangle on my mobile's screen


For some reason your view doesn't work in RelativeLayout. For landscape orientation measurement ends up with following constraints (on my phone):

width = MeasureSpec: EXACTLY 404; height = MeasureSpec: AT_MOST 388

Because of this actual width ends up different than measured width (on my phone measured=388, actual=404). That's why you see background extending beyond your rect. You can check it yourself by adding some logging to onDraw and onMeasure.

Also, respecting measure mode doesn't help, measurement still ends with same result as above.

The solution is to use a different layout. LinearLayout and FrameLayout worked for me. Also it's a good idea to use actual view size in onDraw, with getWidth() and getHeight().

If you really need the RelativeLayout, you can add a child FrameLayout to hold your view like this:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >
    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
        <view
            android:id="@+id/view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            class="com.peerkesoftware.nanograms.controls.GameBoard"
            android:background="@android:color/holo_purple" />
    </FrameLayout>
</RelativeLayout>