Android:为什么视图没有maxHeight?


184

视图有一个,minHeight但不知为何缺少一个maxHeight

我想要达到的目的是要填充一些项目(视图)ScrollView。当有1..3项目时,我想直接显示它们。表示ScrollView的高度为1、2或3个项目。

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

但是,很遗憾,无法设置maxHeight。因此,我可能必须以ScrollView编程方式将高度设置为WRAP_CONTENT存在1..3项时的高度,或者将高度设置为3*sizeOf(View)存在四个或更多项时的高度。

任何人都可以解释为什么已经没有maxHeight提供了minHeight吗?

(顺便说一句:有些视图,例如ImageViewmaxHeight实现。)


我已经张贴在其他线程的解决方案: stackoverflow.com/questions/18425758/...
JMPergar


Google删除maxHeight既烦人又不方便。查看您现在要做的所有事情以得到相同的结果。
伊恩·旺巴

Answers:


86

这些解决方案都无法满足我的需要,这是将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
什么时候不工作?这似乎是一个非常干净的解决方案。让我想知道为什么他们没有将其实现到xml中。
Christophe Smet 2014年

1
如果您手动将高度设置为240,则可能无法正常工作。我不必担心滚动视图所处的模式,因为我只需要支持1种特定模式(wrap_content)。
微风

该答案有一个编辑内容,内容是“如果滚动视图下方存在某些布局,则此技巧将不起作用”,这是不正确的。我有一个与页面底部对齐的布局,此自定义布局具有“ android:layout_above ='@ + ...'”,它始终将自定义布局放在底部布局上方:)
Machine Tribe

70

为了创建一个maxHeight ScrollViewListView一个maxHeight,您只需要围绕它创建一个Transparent LinearLayout,其高度为您想要的maxHeight即可。然后,将ScrollView的Height设置为wrap_content。这将创建一个ScrollView,看起来一直在增长,直到其高度等于父级LinearLayout。


3
这对于防止带有滚动内容的对话框扩展到屏幕的整个高度非常有用。
凯尔·艾维

小建议是使用FrameLayout而不是LinearLayout,但是我怀疑这很重要。
凯尔·艾维

43
如果滚动视图下方存在某些布局,则此技巧将无效
Sreedhu Madhu 2014年

2
您能提供一些代码吗?它对我不起作用,所以也许我在做错什么...
android开发人员

如果下方有按钮,将无法使用。它将按钮推离屏幕
Li Tian Gong

43

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

创建自定义视图绝对是实现此目的的最佳方法。
Bertram Gilfoyle

如果您在滚动视图下面有布局,这将起作用!完善!
Ragaisis

25

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

ConstraintLayout通过以下方式为其子级提供最大高度

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

要么

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

示例用法在这里


2
如果视图位于垂直链中(如ConstraintLayout文档中所指定),则此方法将
无效

谢谢(你的)信息。
user1506104

8

如果可以的话,我会评论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);
}

这样可以将布局调整为小于最大高度,但也可以防止其大于最大高度。我使用了这是一个Overrides的布局类,RelativeLayout这使我可以创建一个带有的自定义对话框,ScrollView因为它的子级MaxHeightRelativeLayout不会扩大屏幕的整个高度,也不会缩小以适合Android多窗口中最小的寡妇尺寸N.


4

无法设置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));

4

用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>

1
确实是完美的解决方案。聪明简单。它甚至适用于recyclerview。
Alex Belets

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>

2

我在这里有一个答案:

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

2

如上所述,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用法完全相同。


1

您是否尝试过使用layout_weight值?如果将其中一个设置为大于0的值,它将将该视图扩展到可用的剩余空间。

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

因此,如果您将两个视图都设置为layout_weight值1,则它们都将拉伸以填充该空间,但它们都将拉伸至相等的空间。如果将其中一个设置为2,则它将是另一个视图的两倍。

这里列出了一些更多信息,位于“线性布局”下。


1
权重的问题在于它们是相对的。不同的屏幕尺寸,不同的结果(例如,对于800px的屏幕),我可以将权重设置为某个值,以便特定区域最终达到所需的200px。但是,在850像素的屏幕上,特定区域最终会大于200像素,但是封闭的元素仍然只有200像素。这就是为什么我更喜欢将maxHeight其设置为特定的倾角值的原因。(我最终以编程方式计算并设置了高度)
znq

1

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


8
您不想将尺寸设置为“ px”。您很可能无法在多个设备上获得所需的结果。developer.android.com/guide/topics/resources/...
Hernd DerBeld

@HerndDerBeld就是它在代码中的工作方式。如果愿意,您始终可以轻松地将DP转换为像素:float pixel = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dp,context.getResources().getDisplayMetrics());
android开发人员

1

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

如果设置最大高度,则可能会迫使视图无法获得足够的空间或占用更少的空间。我知道有时似乎在实际中设置最大高度。但是,如果分辨率会发生巨大变化,并且会发生变化,那么具有最大高度的视图将显得不合适。

我认为没有正确的方法来准确地进行所需的布局。我建议您使用布局管理器和相关机制来考虑布局。我不知道您要达到什么目的,但对我来说有点奇怪,一个列表仅显示三个项目,然后用户必须滚动。

顺便说一句 不能保证minHeight(也许也不应该存在)。强制项目可见而其他相对项目变小可能会有一些好处。


6
错了 按照这种逻辑,您也不能说android:layout_width =“ 500dp”。
Glenn Maynard

我看不出您的逻辑解释有什么问题。如果您设置layout_width(有时可以),则不能保证您能做到。500dp可能在一台设备上合适,而另一台设备上不合适。布局经理!也许您可以解释更多的bcs否决票问题:)
Diego Frehner,

3
说android:maxWidth =“ 500dp”与说android:layout_width =“ 500dp”同样有效。它们都在视图上强制使用特定尺寸。
Glenn Maynard

1

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

setLayoutParams(new LayoutParams(Y, X );

请记住要考虑到设备显示屏的密度,否则在不同设备上可能会得到非常奇怪的行为。例如:

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

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

0

如果你们想制作一个非溢出的scrollview或listview,只不过要在RelativeLayout上,并在其顶部和底部分别具有顶视图和底视图:

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

这需要更多的信誉。具体但简单的实现。
路加·艾里森

0

我使用了Kotlin制作的自定义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>
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.