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

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

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

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

有什么建议吗?

【问题讨论】:

    标签: android view width android-linearlayout


    【解决方案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_width="wrap_content"
        android:layout_height="match_parent"
        android:maxWidth="350dp"
    />
    …
    

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

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

    【讨论】:

      【解决方案2】:

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

      android:layout_width="0dp"
      app:layout_constraintWidth_default="spread"
      app:layout_constraintWidth_max="640dp"
      

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

      【讨论】:

        【解决方案3】:

        这是一个简单的答案,

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

            <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" />
        

        按钮的父级设置为包裹内容,因此会缩小,但最大宽度为 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_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>
        

        还有 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_width="900dp" 时出现错误
        • @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) 的原始答案的基础上,我会进行一些更改(如下所述)。

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

        2. 我会先调用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 的答案很有效。
        猜你喜欢
        • 2012-01-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-11
        • 2014-10-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多