Setting a maximum width on a ViewGroup Setting a maximum width on a ViewGroup android android

Setting a maximum width on a ViewGroup


One option which is what I did is to extend LinearLayout and override the onMeasure function. For example:

public class BoundedLinearLayout extends LinearLayout {    private final int mBoundedWidth;    private final int mBoundedHeight;    public BoundedLinearLayout(Context context) {        super(context);        mBoundedWidth = 0;        mBoundedHeight = 0;    }    public BoundedLinearLayout(Context context, AttributeSet attrs) {        super(context, attrs);        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.BoundedView);        mBoundedWidth = a.getDimensionPixelSize(R.styleable.BoundedView_bounded_width, 0);        mBoundedHeight = a.getDimensionPixelSize(R.styleable.BoundedView_bounded_height, 0);        a.recycle();    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        // Adjust width as necessary        int measuredWidth = MeasureSpec.getSize(widthMeasureSpec);        if(mBoundedWidth > 0 && mBoundedWidth < measuredWidth) {            int measureMode = MeasureSpec.getMode(widthMeasureSpec);            widthMeasureSpec = MeasureSpec.makeMeasureSpec(mBoundedWidth, measureMode);        }        // Adjust height as necessary        int measuredHeight = MeasureSpec.getSize(heightMeasureSpec);        if(mBoundedHeight > 0 && mBoundedHeight < measuredHeight) {            int measureMode = MeasureSpec.getMode(heightMeasureSpec);            heightMeasureSpec = MeasureSpec.makeMeasureSpec(mBoundedHeight, measureMode);        }        super.onMeasure(widthMeasureSpec, heightMeasureSpec);    }}

Then you XML would use the custom class:

<com.yourpackage.BoundedLinearLayout    xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    android:layout_width="fill_parent"    android:layout_height="wrap_content"    android:orientation="vertical"    app:bounded_width="900dp">    <TextView        android:layout_width="fill_parent"        android:layout_height="wrap_content"    /></com.youpackage.BoundedLinearLayout>

And the attr.xml file entry

<declare-styleable name="BoundedView">    <attr name="bounded_width" format="dimension" />    <attr name="bounded_height" format="dimension" /></declare-styleable>

EDIT: This is the actual code I am using now. This is still not complete but works in most cases.


Here is better code for the Dori's answer.

In method onMeasure, If you call super.onMeasure(widthMeasureSpec, heightMeasureSpec); first in the method then all objects' width in the layout will not be changed. Because they initialized before you set the layout(parent) width.

public class MaxWidthLinearLayout extends LinearLayout {    private final int mMaxWidth;    public MaxWidthLinearLayout(Context context) {        super(context);        mMaxWidth = 0;    }    public MaxWidthLinearLayout(Context context, AttributeSet attrs) {        super(context, attrs);        TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.MaxWidthLinearLayout);        mMaxWidth = a.getDimensionPixelSize(R.styleable.MaxWidthLinearLayout_maxWidth, Integer.MAX_VALUE);        a.recycle();    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        int measuredWidth = MeasureSpec.getSize(widthMeasureSpec);        if (mMaxWidth > 0 && mMaxWidth < measuredWidth) {            int measureMode = MeasureSpec.getMode(widthMeasureSpec);            widthMeasureSpec = MeasureSpec.makeMeasureSpec(mMaxWidth, measureMode);        }        super.onMeasure(widthMeasureSpec, heightMeasureSpec);    }}

And here is a link for usage of xml attr:
 http://kevindion.com/2011/01/custom-xml-attributes-for-android-widgets/

Thanks for this question and answers. Your answer has helped me a lot, and I hope it helps somebody else in the future as well.


Building on top of the original answer by Chase (+1) I would make a couple of changes (outlined below).

  1. I would have the max width set via a custom attribute (xml below the code)

  2. I would call super.measure() first and then do the Math.min(*) comparison. Using the original answers code we may encounter problems when the incoming size set in the MeasureSpec is either LayoutParams.WRAP_CONTENT or LayoutParams.FILL_PARENT. As these valid constants have values of -2 and -1 respectivly, the original Math.min(*) becomes useless as it will preserve these vales over the max size, and say the measured WRAP_CONTENT is bigger than our max size this check would not catch it. I imagine the OP was thinking of exact dims only (for which it works great)

    public class MaxWidthLinearLayout extends LinearLayout {private int mMaxWidth = Integer.MAX_VALUE;public MaxWidthLinearLayout(Context context) {    super(context);}public MaxWidthLinearLayout(Context context, AttributeSet attrs) {    super(context, attrs);    TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.MaxWidthLinearLayout);    mMaxWidth = a.getDimensionPixelSize(R.styleable.MaxWidthLinearLayout_maxWidth, Integer.MAX_VALUE);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {    super.onMeasure(widthMeasureSpec, heightMeasureSpec);    //get measured height    if(getMeasuredWidth() > mMaxWidth){        setMeasuredDimension(mMaxWidth, getMeasuredHeight());    }}}

and the xml attr

    <!-- MaxWidthLinearLayout -->    <declare-styleable name="MaxWidthLinearLayout">        <attr name="maxWidth" format="dimension" />    </declare-styleable>