Android:为什么视图没有maxHeight?

时间:2010-10-29 17:57:57

标签: android layout view autoresize

View's have a minHeight但不知何故缺少maxHeight

我想要实现的是让一些项目(视图)填满ScrollView。当有1..3项时,我想直接显示它们。这意味着ScrollView的高度为1,2或3个项目。

如果有4个或更多项目,我希望ScrollView停止展开(因此为maxHeight)并开始提供滚动功能。

但遗憾的是,无法设置maxHeight。因此,当有1个项目时,我可能必须以编程方式将ScrollView高度设置为WRAP_CONTENT,并且当有4个或更多项目时,将高度设置为3*sizeOf(View)

当有maxHeight时,有人可以解释为什么没有提供minHeight吗?

(顺便说一句:有些观点,例如ImageView已实施maxHeight。)

17 个答案:

答案 0 :(得分:77)

这些解决方案都不适用于我需要的东西,这是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 3月5日4:36

答案 1 :(得分:68)

要使用maxHeight创建ScrollViewListView,您只需要在其周围创建一个透明LinearLayout,其高度为maxHeight的高度。然后,将ScrollView的高度设置为wrap_content。这会创建一个ScrollView,它看起来会增长,直到它的高度等于父LinearLayout。

答案 2 :(得分:35)

这对我来说可以在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>

答案 3 :(得分:10)

(我知道这不会直接回答这个问题,但可能对寻求maxHeight功能的其他人有所帮助)

ConstraintLayout通过

为其子女提供最大身高
app:layout_constraintHeight_max="300dp"
app:layout_constrainedHeight="true" 

app:layout_constraintWidth_max="300dp"
app:layout_constrainedWidth="true" 

示例用法here

答案 4 :(得分:6)

如果可以的话,我会对whizzle的答案发表评论,但认为有必要注意,为了让我在Android N的多窗口模式环境中解决这个问题,我需要稍微改变代码:

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

这允许布局调整大小小于最大高度,但也防止布局大于最大高度。我使用过这是一个覆盖RelativeLayout的布局类,这允许我创建一个自定义对话框,ScrollView作为MaxHeightRelativeLayout的子级,不会扩展屏幕的整个高度也缩小到适合Android N的多窗口中最小的寡妇尺寸。

答案 5 :(得分:3)

无法设置maxHeight。但你可以设置高度。

要做到这一点,您需要发现scrollView的每个项目的高度。之后,只需将scrollView高度设置为numberOfItens * heightOfItem。

要发现项目的高度,请执行以下操作:

View item = adapter.getView(0, null, scrollView);
item.measure(0, 0);
int heightOfItem = item.getMeasuredHeight();

要设置高度,请执行以下操作:

// if the scrollView already has a layoutParams:
scrollView.getLayoutParams().height = heightOfItem * numberOfItens;
// or
// if the layoutParams is null, then create a new one.
scrollView.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, heightOfItem * numberOfItens));

答案 6 :(得分:3)

我的MaxHeightScrollView自定义视图

public class MaxHeightScrollView extends ScrollView {
    private int maxHeight;

    public MaxHeightScrollView(Context context) {
        this(context, null);
    }

    public MaxHeightScrollView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

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

    private void init(Context context, AttributeSet attrs) {
        TypedArray styledAttrs =
                context.obtainStyledAttributes(attrs, R.styleable.MaxHeightScrollView);
        try {
            maxHeight = styledAttrs.getDimensionPixelSize(R.styleable.MaxHeightScrollView_mhs_maxHeight, 0);
        } finally {
            styledAttrs.recycle();
        }
    }

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

<强> style.xml

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

<....MaxHeightScrollView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:mhs_maxHeight="100dp"
    >

    ...

</....MaxHeightScrollView>

答案 7 :(得分:1)

我们知道运行android的设备可以有不同的屏幕尺寸。我们进一步知道视图应该动态调整并成为合适的空间。

如果设置了最大高度,可能会强制视图无法获得足够的空间或占用更少的空间。我知道有时似乎实际上设置了最大高度。但是如果分辨率会发生巨大变化,那么它将会发生变化!那么具有最大高度的视图将看起来不合适。

我认为没有正确的方法可以完全按照您的要求进行布局。我建议你使用布局管理器和相关机制来思考你的布局。我不知道你想要实现什么,但对我来说,一个列表应该只显示三个项目,然后用户必须滚动,这听起来有点奇怪。

顺便说一句。 minHeight不保证(也许不应该存在)。当其他相关项目变小时,强制项目可以有一些好处。

答案 8 :(得分:1)

如果有人考虑使用LayoutParams的确切值,例如

setLayoutParams(new LayoutParams(Y, X );

请记住考虑设备显示屏的密度,否则您可能会在不同的设备上出现非常奇怪的行为。 E.g:

Display display = getWindowManager().getDefaultDisplay();
DisplayMetrics d = new DisplayMetrics();
display.getMetrics(d);
setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, (int)(50*d.density) ));

答案 9 :(得分:1)

您是否尝试过使用layout_weight value?如果将其设置为大于0的值,则会将该视图拉伸到剩余的可用空间中。

如果您有多个需要拉伸的视图,那么该值将成为它们之间的权重。

因此,如果你有两个视图都设置为layout_weight值为1,那么它们都会伸展以填充空间,但它们都会延伸到相等的空间。如果将其中一个设置为值2,那么它将拉伸两倍于另一个视图。

Some more info here listed under Linear Layout.

答案 10 :(得分:1)

使用layout_height =“max_height”将您的ScrollView包裹在普通LinearLayout周围,这样做会很完美。事实上,我在过去的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>

答案 11 :(得分:1)

我在这里有一个答案:

https://stackoverflow.com/a/29178364/1148784

只需创建一个扩展ScrollView的新类并重写其onMeasure方法即可。

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (maxHeight > 0){
            int hSize = MeasureSpec.getSize(heightMeasureSpec);
            int hMode = MeasureSpec.getMode(heightMeasureSpec);

            switch (hMode){
                case MeasureSpec.AT_MOST:
                    heightMeasureSpec = MeasureSpec.makeMeasureSpec(Math.min(hSize, maxHeight), MeasureSpec.AT_MOST);
                    break;
                case MeasureSpec.UNSPECIFIED:
                    heightMeasureSpec = MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.AT_MOST);
                    break;
                case MeasureSpec.EXACTLY:
                    heightMeasureSpec = MeasureSpec.makeMeasureSpec(Math.min(hSize, maxHeight), MeasureSpec.EXACTLY);
                    break;
            }
        }

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

答案 12 :(得分:0)

如果你们想制作一个非溢出的滚动视图或列表视图,只需在它上面和顶部有一个顶视图和底视图的RelativeLayout:

<ScrollView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_above="@+id/topview"
    android:layout_below="@+id/bottomview" >

答案 13 :(得分:0)

我使用了Kotlin制造的custom ScrollView,其中使用了maxHeight。使用示例:

<com.antena3.atresplayer.tv.ui.widget.ScrollViewWithMaxHeight
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:maxHeight="100dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
</com.antena3.atresplayer.tv.ui.widget.ScrollViewWithMaxHeight>

这是ScrollViewWidthMaxHeight的代码:

import android.content.Context
import android.util.AttributeSet
import android.widget.ScrollView
import timber.log.Timber

class ScrollViewWithMaxHeight @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : ScrollView(context, attrs, defStyleAttr) {

companion object {
    var WITHOUT_MAX_HEIGHT_VALUE = -1
}

private var maxHeight = WITHOUT_MAX_HEIGHT_VALUE

init {
    val a = context.obtainStyledAttributes(
        attrs, R.styleable.ScrollViewWithMaxHeight,
        defStyleAttr, 0
    )
    try {
        maxHeight = a.getDimension(
            R.styleable.ScrollViewWithMaxHeight_android_maxHeight,
            WITHOUT_MAX_HEIGHT_VALUE.toFloat()
        ).toInt()
    } finally {
        a.recycle()
    }
}

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
    var heightMeasure = heightMeasureSpec
    try {
        var heightSize = MeasureSpec.getSize(heightMeasureSpec)
        if (maxHeight != WITHOUT_MAX_HEIGHT_VALUE) {
            heightSize = maxHeight
            heightMeasure = MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.AT_MOST)
        } else {
            heightMeasure = MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.UNSPECIFIED)
        }
        layoutParams.height = heightSize
    } catch (e: Exception) {
        Timber.e(e, "Error forcing height")
    } finally {
        super.onMeasure(widthMeasureSpec, heightMeasure)
    }
}

fun setMaxHeight(maxHeight: Int) {
    this.maxHeight = maxHeight
}
}

values/attrs.xml中也需要此声明:

<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="ScrollViewWithMaxHeight">
        <attr name="android:maxHeight" />
    </declare-styleable>
</resources>

答案 14 :(得分:0)

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

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

此外,如果一个ConstraintLayout子级的最大高度在应用程序运行之前不确定,那么无论将其放置在垂直链中的哪个位置,仍有一种方法使该子级自动适应可变高度。

例如,我们需要显示一个底部对话框,其中包含可变的标题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的水平用法完全相同。

答案 15 :(得分:0)

首先获取项目高度(以像素为单位)

View rowItem = adapter.getView(0, null, scrollView);   
rowItem.measure(0, 0);    
int heightOfItem = rowItem.getMeasuredHeight();

然后简单地

Display display = getWindowManager().getDefaultDisplay();    
DisplayMetrics displayMetrics = new DisplayMetrics();    
display.getMetrics(displayMetrics);    
scrollView.getLayoutParams().height = (int)((heightOfItem * 3)*displayMetrics .density);

答案 16 :(得分:0)

我认为您可以在运行时为{1}}设置1个项目的高度,为2个项scrollView.setHeight(200px)设置3个或更多scrollView.setheight(400px)