How to size an Android view based on its parent's dimensions
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).
You could solve this by creating a custom View and override the onMeasure() method. If you always use "fill_parent" for the layout_width in your xml then the widthMeasureSpec parameter that is passed into the onMeasusre() method should contain the width of the parent.
public class MyCustomView extends TextView {
public MyCustomView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
this.setMeasuredDimension(parentWidth / 2, parentHeight);
}
}
Your XML would look something like this:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<view
class="com.company.MyCustomView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
I've found that it's best not to mess around with setting the measured dimensions yourself. There's actually a bit of negotiation that goes on between the parent and child views and you don't want to re-write all that code.
What you can do, though, is modify the measureSpecs, then call super with them. Your view will never know that it's getting a modified message from its parent and will take care of everything for you:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
int myWidth = (int) (parentHeight * 0.5);
super.onMeasure(MeasureSpec.makeMeasureSpec(myWidth, MeasureSpec.EXACTLY), heightMeasureSpec);
}