视图有minHeight,但不知何故缺少maxHeight:

我要实现的是有一些项目(视图)填充一个ScrollView。当有1..3个项目,我想直接显示他们。意思是ScrollView有1,2或3个项的高度。

当有4个或更多的项目时,我希望ScrollView停止展开(因此是maxHeight)并开始提供滚动。

然而,不幸的是,没有办法设置maxHeight。所以我可能需要通过编程方式将ScrollView的高度设置为WRAP_CONTENT当有1。当有4个或更多的项目时,设置高度为3*sizeOf(视图)。

有人能解释为什么没有maxHeight提供,当已经有一个minHeight?

(BTW:一些视图,如ImageView有一个maxHeight实现。)


当前回答

这对我来说是有效的,使它在xml中可定制:

MaxHeightScrollView.java:

public class MaxHeightScrollView extends ScrollView {

private int maxHeight;
private final int defaultHeight = 200;

public MaxHeightScrollView(Context context) {
    super(context);
}

public MaxHeightScrollView(Context context, AttributeSet attrs) {
    super(context, attrs);
    if (!isInEditMode()) {
        init(context, attrs);
    }
}

public MaxHeightScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    if (!isInEditMode()) {
        init(context, attrs);
    }
}

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public MaxHeightScrollView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    super(context, attrs, defStyleAttr, defStyleRes);
    if (!isInEditMode()) {
        init(context, attrs);
    }
}

private void init(Context context, AttributeSet attrs) {
    if (attrs != null) {
        TypedArray styledAttrs = context.obtainStyledAttributes(attrs, R.styleable.MaxHeightScrollView);
        //200 is a defualt value
        maxHeight = styledAttrs.getDimensionPixelSize(R.styleable.MaxHeightScrollView_maxHeight, defaultHeight);

        styledAttrs.recycle();
    }
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    heightMeasureSpec = MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.AT_MOST);
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}

attr.xml

<declare-styleable name="MaxHeightScrollView">
        <attr name="maxHeight" format="dimension" />
    </declare-styleable>

示例布局

<blah.blah.MaxHeightScrollView android:layout_weight="1"
                app:maxHeight="90dp"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content">
                <EditText android:id="@+id/commentField"
                    android:hint="Say Something"
                    android:background="#FFFFFF"
                    android:paddingLeft="8dp"
                    android:paddingRight="8dp"
                    android:gravity="center_vertical"
                    android:maxLines="500"
                    android:minHeight="36dp"
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content" />
            </blah.blah.MaxHeightScrollView>

其他回答

如上所述,ConstraintLayout通过以下方式为其子节点提供最大高度:

app:layout_constraintHeight_max="300dp"
app:layout_constrainedHeight="true"

此外,如果一个ConstraintLayout的子节点的最大高度在App运行之前是不确定的,那么仍然有一种方法可以让这个子节点自动适应一个可变的高度,无论它被放置在垂直链的哪个位置。

例如,我们需要显示一个底部对话框,一个可变的头部TextView,一个可变的ScrollView和一个可变的页脚TextView。对话框的最大高度是320dp,当总高度没有达到320dp时,ScrollView作为wrap_content,当总高度超过ScrollView时,作为“maxHeight=320dp -头高-脚高”。

我们可以通过xml布局文件来实现这一点:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="320dp">

    <TextView
        android:id="@+id/tv_header"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/black_10"
        android:gravity="center"
        android:padding="10dp"
        app:layout_constraintBottom_toTopOf="@id/scroll_view"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="1"
        app:layout_constraintVertical_chainStyle="packed"
        tools:text="header" />

    <ScrollView
        android:id="@+id/scroll_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/black_30"
        app:layout_constrainedHeight="true"
        app:layout_constraintBottom_toTopOf="@id/tv_footer"
        app:layout_constraintHeight_max="300dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/tv_header">

        <LinearLayout
            android:id="@+id/ll_container"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <TextView
                android:id="@+id/tv_sub1"
                android:layout_width="match_parent"
                android:layout_height="160dp"
                android:gravity="center"
                android:textColor="@color/orange_light"
                tools:text="sub1" />

            <TextView
                android:id="@+id/tv_sub2"
                android:layout_width="match_parent"
                android:layout_height="160dp"
                android:gravity="center"
                android:textColor="@color/orange_light"
                tools:text="sub2" />

        </LinearLayout>
    </ScrollView>

    <TextView
        android:id="@+id/tv_footer"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/black_50"
        android:gravity="center"
        android:padding="10dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/scroll_view"
        tools:text="footer" />
</android.support.constraint.ConstraintLayout>

大多数导入代码都很短:

app:layout_constraintVertical_bias="1"
app:layout_constraintVertical_chainStyle="packed"

app:layout_constrainedHeight="true"

横向maxWidth的使用是完全相同的。

这些解决方案都没有为我所需要的是一个ScrollView设置为wrap_content,但有一个maxHeight,因此它将在某一点后停止展开并开始滚动。我只是简单地覆盖了ScrollView中的onMeasure方法。

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    heightMeasureSpec = MeasureSpec.makeMeasureSpec(300, MeasureSpec.AT_MOST);
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

这可能不是在所有情况下都有效,但它确实为我的布局提供了所需的结果。它也提到了madhu的评论。

如果在滚动视图下面出现一些布局,那么这个技巧将不起作用- madhu Mar 5 at 4:36

用layout_height="max_height"包装你的ScrollView围绕你的plainLinearLayout,这将做一个完美的工作。事实上,我在过去5年里一直在生产中使用这个代码,没有任何问题。

<LinearLayout
        android:id="@+id/subsParent"
        android:layout_width="match_parent"
        android:layout_height="150dp"
        android:gravity="bottom|center_horizontal"
        android:orientation="vertical">

        <ScrollView
            android:id="@+id/subsScroll"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="10dp"
            android:layout_marginEnd="15dp"
            android:layout_marginStart="15dp">

            <TextView
                android:id="@+id/subsTv"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/longText"
                android:visibility="visible" />

        </ScrollView>
    </LinearLayout>

我认为你可以在运行时设置高度为1项scrollView.setHeight(200px),为2项scrollView.setHeight(400px)为3或更多的scrollView.setHeight(600px)

以防有人需要:

app:layout_constraintHeight_max="300dp"

它强制视图(在ConstraintLayout中)的最大高度为300dp。对于那些想要通过编程来实现这一点的人来说,它是这样的:

val totalScreenHeight = displayMetrics.heightPixels
val layoutParams: ConstraintLayout.LayoutParams = viewThatIsInsideAConstraintLayout.layoutParams as ConstraintLayout.LayoutParams
        layoutParams.matchConstraintMaxHeight = totalScreenHeight/2
viewThatIsInsideAConstraintLayout.layoutParams = layoutParams