Android: почему нет maxHeight для просмотра?

Вид естьminHeight но почему-то не хватает maxHeight:

Я пытаюсь добиться того, чтобы некоторые элементы (представления) заполняли ScrollView, Когда есть элементы 1..3, я хочу отобразить их напрямую. Значение ScrollView имеет высоту 1, 2 или 3 предметов.

Когда есть 4 или более предметов, я хочу ScrollView прекратить расширение (таким образом, maxHeight) и начните предоставлять прокрутку.

Однако, к сожалению, нет способа установить maxHeight, Так что я, вероятно, должен установить мой ScrollView высота программно либо WRAP_CONTENT когда есть 1..3 пунктов и установите высоту 3*sizeOf(View) когда есть 4 или более предметов.

Может кто-нибудь объяснить, почему нет maxHeight при условии, что уже есть minHeight?

(Кстати: некоторые взгляды, как ImageView иметь maxHeight реализовано.)

18 ответов

Ни одно из этих решений не работало для того, что мне было нужно, для ScrollView было установлено значение wrap_content, но имел maxHeight, чтобы он прекратил расширение после определенной точки и начал прокрутку. Я просто переопределил метод onMeasure в ScrollView.

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

Это может работать не во всех ситуациях, но, безусловно, дает мне результаты, необходимые для моего макета. И это также обращается к комментарию Madhu.

Если какой-то макет присутствует ниже прокрутки, тогда этот трюк не сработает - Мадху 5 марта в 4:36

Для того, чтобы создать ScrollView или же ListView с maxHeight вам просто нужно создать прозрачный LinearLayout вокруг него с высотой, которую вы хотите, чтобы maxHeight был. Затем вы устанавливаете высоту ScrollView на wrap_content, Это создает ScrollView, который, кажется, растет, пока его высота не станет равной родительскому LinearLayout.

Это помогло мне настроить его в 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>

(Я знаю, что это не дает прямого ответа на вопрос, но может быть полезным для тех, кто ищет функциональность maxHeight)

ConstraintLayout предлагает максимальную высоту для своих детей через

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

или же

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

Пример использования здесь.

Я бы прокомментировал ответ 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.

Как упоминалось выше, ConstraintLayout предлагает максимальную высоту для своих дочерних элементов через:

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

Кроме того, если максимальная высота для одного дочернего элемента ConstraintLayout не определена до запуска приложения, все еще есть способ заставить этот дочерний элемент автоматически адаптировать изменяемую высоту независимо от того, где он был размещен в вертикальной цепочке.

Например, нам нужно показать нижний диалог с изменяемым заголовком TextView, изменяемым ScrollView и изменяемым нижним колонтитулом TextView. Максимальная высота диалога составляет 320dp,, когда общая высота не достигает 320 dp. 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 вокруг вашей равниныLinearLayout с layout_height="max_height" это отлично подойдет. На самом деле, у меня есть этот код в производстве за последние 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>

Нет способа установить 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));

У меня есть ответ:

/questions/25599032/kak-ustanovit-maksimalnuyu-vyisotu-s-soderzhimyim-perenosa-v-android/25599050#25599050

Просто создайте новый класс, расширяющий 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);
    }

Мой 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>

Если кому-то это нужно:

      app:layout_constraintHeight_max="300dp"

Он заставляет View (который находится внутри ConstraintLayout) иметь максимальную высоту 300dp. Для тех, кто хочет сделать это программно, это выглядит так:

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

Я думаю, что вы можете установить heiht во время выполнения для 1 элемента просто scrollView.setHeight(200px), на 2 предмета scrollView.setheight(400px) на 3 или более scrollView.setHeight(600px)

Если кто-то рассматривает возможность использования точного значения для 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) ));

Вы пытались использовать значение layout_weight? Если вы установите его на значение больше 0, он будет растягивать это представление на оставшееся свободное место.

Если у вас было несколько видов, которые нужно растянуть, то значение станет весом между ними.

Таким образом, если бы у двух представлений было установлено значение layout_weight, равное 1, они оба растянулись бы, чтобы заполнить пространство, но оба растянулись бы до равного количества места. Если вы установите один из них в значение 2, то он будет растягиваться вдвое больше, чем другой вид.

Некоторая дополнительная информация здесь указана в разделе "Линейный макет".

Сначала получите высоту элемента в пикселях

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

Я использовал собственный ScrollView, сделанный в Kotlin, который использует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>

Как мы знаем, устройства под управлением Android могут иметь разные размеры экрана. Как мы далее знаем, представления должны корректироваться динамически и стать подходящим пространством.

Если вы установите максимальную высоту, вы можете заставить вид не получить достаточно места или занять меньше места. Я знаю, что иногда кажется, что практически установить максимальную высоту. Но если разрешение когда-либо резко изменится, и оно изменится!, то представление с максимальной высотой будет выглядеть неуместно.

Я думаю, что нет правильного способа сделать макет, который вы хотите. Я бы порекомендовал вам продумать макет, используя менеджеры макетов и соответствующие механизмы. я не знаю, чего вы пытаетесь достичь, но для меня немного странно, что список должен содержать только три элемента, а затем пользователь должен прокрутить.

Кстати. minHeight не гарантируется (и, возможно, не должно существовать). это может иметь некоторое преимущество, чтобы заставить элементы быть видимыми, в то время как другие относительные элементы становятся меньше.

Если вы, ребята, хотите сделать прокрутку без просмотра или просмотр списка без переполнения, просто используйте RelativeLayout с видом сверху и снизу сверху и снизу:

<ScrollView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_above="@+id/topview"
    android:layout_below="@+id/bottomview" >
Другие вопросы по тегам