Setting a maximum width on a ViewGroup
How do I set the maximum width of a ViewGroup? I am using a Theme.Dialog
activity, however, this does not look so good when resized to bigger screens, it's also sort of lightweight and I don't want it taking up the whole screen.
I tried this suggestion to no avail. Also, there is no android:maxWidth
property like some views.
Is there a way to restri开发者_运维问答ct the root LinearLayout so that it is only (for example) 640 dip? I am willing to change to another ViewGroup for this.
Any suggestions?
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).
I would have the max width set via a custom attribute (xml below the code)
I would call
super.measure()
first and then do theMath.min(*)
comparison. Using the original answers code we may encounter problems when the incoming size set in theMeasureSpec
is eitherLayoutParams.WRAP_CONTENT
orLayoutParams.FILL_PARENT
. As these valid constants have values of -2 and -1 respectivly, the originalMath.min(*)
becomes useless as it will preserve these vales over the max size, and say the measuredWRAP_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); } @Override protected 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>
Now android.support.constraint.ConstraintLayout
makes it easier. Just wrap your view (of any type) with ConstraintLayout, and set the following attributes to the view:
android:layout_width="0dp"
app:layout_constraintWidth_default="spread"
app:layout_constraintWidth_max="640dp"
http://tools.android.com/recent/constraintlayoutbeta5isnowavailable
Here's a pure Kotlin solution, with the added benefit of being able to use android:maxWidth
.
BoundedFrameLayout.kt
package example.com
import android.content.Context
import android.util.AttributeSet
import android.widget.FrameLayout
import androidx.core.content.withStyledAttributes
import com.sas.android.common.R
class BoundedFrameLayout @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr) {
private var maxWidth = -1
init {
if (attrs != null) {
context.withStyledAttributes(attrs, R.styleable.BoundedView) {
maxWidth = getDimensionPixelSize(
R.styleable.BoundedView_android_maxWidth, maxWidth
)
}
}
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
var widthSpec = widthMeasureSpec
if (maxWidth >= 0) {
val widthSize = MeasureSpec.getSize(widthMeasureSpec)
if (widthSize > maxWidth) {
val widthMode = MeasureSpec.getMode(widthMeasureSpec)
widthSpec = MeasureSpec.makeMeasureSpec(maxWidth, widthMode)
}
}
super.onMeasure(widthSpec, heightMeasureSpec)
}
}
attrs.xml
<resources>
<declare-styleable name="BoundedView">
<attr name="android:maxWidth" />
</declare-styleable>
</resources>
Then in your layout XML:
…
<com.example.BoundedFrameLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:maxWidth="350dp"
/>
…
Max height can be handled in the same way as width; it is omitted here for brevity.
This pattern can be adopted for any ViewGroup subclass (e.g. LinearLayout).
Here is a simple answer,
Width/Height seem to always have to be set together. This is working in my view.
<Button
android:text="Center"
android:layout_width="100dp"
android:layout_height="fill_parent"
android:id="@+id/selectionCenterButton"
android:minWidth="50dp"
android:minHeight="50dp"
android:maxWidth="100dp"
android:maxHeight="50dp"
android:layout_weight="1" />
The button's parent is set to wrap content, so scales down, but up to a max of 400 wide (4 buttons).
精彩评论