在 ViewGroup 上设置最大宽度

Posted

技术标签:

【中文标题】在 ViewGroup 上设置最大宽度【英文标题】:Setting a maximum width on a ViewGroup 【发布时间】:2011-08-18 01:36:21 【问题描述】:

如何设置 ViewGroup 的最大宽度?我正在使用Theme.Dialog 活动,但是,当调整到更大的屏幕时,它看起来不太好,它也有点轻巧,我不希望它占据整个屏幕。

我试过this suggestion 无济于事。此外,没有像某些视图那样的android:maxWidth 属性。

有没有办法限制根 LinearLayout 使其仅(例如)640 dip?我愿意为此更改为另一个 ViewGroup。

有什么建议吗?

【问题讨论】:

【参考方案1】:

这是一个纯 Kotlin 解决方案,另外还有一个好处是可以使用 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>

然后在你的布局 XML 中:

…
<com.example.BoundedFrameLayout
    android:layout_
    android:layout_
    android:maxWidth="350dp"
/>
…

最大高度可以和宽度一样处理;为简洁起见,此处省略。

此模式可用于任何 ViewGroup 子类(例如 LinearLayout)。

【讨论】:

【参考方案2】:

现在android.support.constraint.ConstraintLayout 更容易了。只需使用 ConstraintLayout 包装您的视图(任何类型),并为视图设置以下属性:

android:layout_
app:layout_constraintWidth_default="spread"
app:layout_constraintWidth_max="640dp"

http://tools.android.com/recent/constraintlayoutbeta5isnowavailable

【讨论】:

【参考方案3】:

这是一个简单的答案,

宽度/高度似乎总是必须一起设置。这在我看来是有效的。

    <Button
        android:text="Center"
        android:layout_
        android:layout_
        android:id="@+id/selectionCenterButton"
        android:minWidth="50dp"
        android:minHeight="50dp"
        android:maxWidth="100dp"
        android:maxHeight="50dp"
        android:layout_weight="1" />

按钮的父级设置为包裹内容,因此会缩小,但最大宽度为 400(4 个按钮)。

【讨论】:

按钮不是 ViewGroup。 ViewGroups 没有 max* 属性。 Button 是 TextView 的子类,它确实具有这些属性。整个问题是关于如何处理没有 max* 属性的视图。【参考方案4】:

我所做的一个选择是扩展 LinearLayout 并覆盖 onMeasure 函数。例如:

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);
    

然后你的 XML 将使用自定义类:

<com.yourpackage.BoundedLinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_
    android:layout_
    android:orientation="vertical"
    app:bounded_>

    <TextView
        android:layout_
        android:layout_
    />
</com.youpackage.BoundedLinearLayout>

还有 attr.xml 文件入口

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

编辑:这是我现在使用的实际代码。这仍然不完整,但在大多数情况下都有效。

【讨论】:

令人难以置信的是,Google 没有开箱即用地包含 maxWidth,而是我们必须继承 :-( 你是绝对正确的。他们正在有效地众包平台:] 添加 app_name:bounded_ 时出现错误 @AHmédNet 将 xmlns:app_name="http://schemas.android.com/apk/res-auto" 添加到布局的顶部元素以解决该问题【参考方案5】:

这是 Dori 答案的更好代码。

在方法onMeasure中,如果在方法中先调用super.onMeasure(widthMeasureSpec, heightMeasureSpec);,那么布局中所有对象的宽度都不会改变。因为它们在您设置布局(父)宽度之前已初始化。

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);
    

这里是xml attr的使用链接:http://kevindion.com/2011/01/custom-xml-attributes-for-android-widgets/

感谢您提出这个问题和答案。您的回答对我有很大帮助,希望以后也能对其他人有所帮助。

【讨论】:

这个答案更好。 (还有为什么 Dori 错过了一个小错误?) 如果在 MaxWidthLinearLayout 的布局参数中指定了精确大小,则内容仍使用原始宽度...您必须指定 MATH_PARENT 并将精确大小管理放入onMeasure(..)。愚蠢但工作。【参考方案6】:

在 Chase (+1) 的原始答案的基础上,我会进行一些更改(如下所述)。

    我将通过自定义属性设置最大宽度(代码下方的 xml)

    我会先调用super.measure(),然后再进行Math.min(*) 比较。当MeasureSpec 中设置的传入大小为LayoutParams.WRAP_CONTENTLayoutParams.FILL_PARENT 时,使用原始答案代码可能会遇到问题。由于这些有效常量的值分别为 -2-1,原来的 Math.min(*) 变得无用,因为它将保留这些值超过最大大小,并说测量WRAP_CONTENT 大于我们的最大尺寸,此检查无法捕捉到它。我想 OP 只考虑精确的暗淡(效果很好)

    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());
        
    
    
    

和xml属性

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

【讨论】:

感谢您的回复。我不再需要这个了,但我相信其他人也可能需要它。如果我觉得我需要修改我的代码,我一定会检查一下! 如果在我忘记我所做的事情的几年内是为了其他人/我:) 此代码无法按预期工作。调整宽度时,包含的元素仍使用原始宽度。因此,内容只是被截断。 Jonypoins 的答案很有效。

以上是关于在 ViewGroup 上设置最大宽度的主要内容,如果未能解决你的问题,请参考以下文章

将高度设置为自定义视图组

2Android-UI(自定义控件&ListView)

这个网站上的最大宽度是如何设置的? [关闭]

如何动态设置ImageView的宽度高度以及位置

如何在 iOS 中设置视图的最大宽度?

使用 Matisse GUI builder 设置最大宽度