How to size an Android view based on its parent's dimensions

Viewed 158898

How can I size a view based on the size of its parent layout. For example I have a RelativeLayout that fills the full screen, and I want a child view, say an ImageView, to take up the whole height, and 1/2 the width?

I've tried overriding all on onMeasure, onLayout, onSizeChanged, etc and I couldn't get it to work....

11 Answers

I don't know if anyone is still reading this thread or not, but Jeff's solution will only get you halfway there (kinda literally). What his onMeasure will do is display half the image in half the parent. The problem is that calling super.onMeasure prior to the setMeasuredDimension will measure all the children in the view based on the original size, then just cut the view in half when the setMeasuredDimension resizes it.

Instead, you need to call setMeasuredDimension (as required for an onMeasure override) and provide a new LayoutParams for your view, then call super.onMeasure. Remember, your LayoutParams are derived from your view's parent type, not your view's type.

@Override 
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
   int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
   int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
   this.setMeasuredDimension(parentWidth/2, parentHeight);
   this.setLayoutParams(new *ParentLayoutType*.LayoutParams(parentWidth/2,parentHeight));
   super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

I believe the only time you'll have problems with the parent LayoutParams is if the parent is an AbsoluteLayout (which is deprecated but still sometimes useful).

When you define a layout and view on XML, you can specify the layout width and height of a view to either be wrap_content, or fill_parent. Taking up half of the area is a bit harder, but if you had something you wanted on the other half you could do something like the following.

<LinearLayout android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <ImageView android:layout_height="fill_parent"
        android:layout_width="0dp"
        android:layout_weight="1" />
    <ImageView android:layout_height="fill_parent"
        android:layout_width="0dp"
        android:layout_weight="1" />
</LinearLayout>

Giving two things the same weight means that they will stretch to take up the same proportion of the screen. For more info on layouts, see the dev docs.

Roman, if you want to do your layout in Java code (ViewGroup descendant), it is possible. The trick is that you have to implement both onMeasure and onLayout methods. The onMeasure gets called first and you need to "measure" the subview (effectively sizing it to the desired value) there. You need to size it again in the onLayout call. If you fail to do this sequence or fail to call setMeasuredDimension() at the end of your onMeasure code, you won't get results. Why is this designed in such complicated and fragile way is beyond me.

I've been struggling this question for a long time, I want to change my DrawerLayout's drawer width, which is the second child of its parent. Recently I figured it out, but doesn't know if there's a better idea.

override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
    super.onLayout(changed, l, t, r, b)
    (getChildAt(1).layoutParams as LayoutParams).width = measuredWidth/2
}
Related