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


184

Перегляд є,minHeight але чомусь не вистачає maxHeight:

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

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

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

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

(BTW: деякі перегляди, як-от ImageView, maxHeightреалізовані.)


Я відправив рішення в іншому потоці: stackoverflow.com/questions/18425758 / ...
JMPergar

2
Я створив рішення для цього на сайті chintanrathod.com/…
Chintan Rathod,

Google видалити maxHeight - це дратує і незручно. Подивіться на всі речі, які вам доведеться зараз зробити, щоб отримати той самий результат.
Ян Вамбай

Відповіді:


86

Жодне з цих рішень не працювало на те, що мені потрібно, а це був 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


1
Коли це не вийшло? Це здається дуже чистим рішенням. Мене здивує, чому вони не втілили його в xml.
Крістоф Смет

1
Це, ймовірно, не буде працювати, якщо ви вручну встановите висоту, щоб сказати 240. Я не переймався переглядом режиму прокрутки, тому що мені потрібно було підтримувати лише 1 певний режим (wrap_content).
свист

Для цієї відповіді є редакція, яка говорить: "Якщо деякий макет присутній під переглядом прокрутки, то цей трюк не буде працювати", що не відповідає дійсності. У мене макет вирівняний в нижній частині сторінки, і цей користувальницький макет має "android: layout_above = '@ + ...'", який завжди розміщує користувацький макет вище нижнього макета :)
Machine Tribe

70

Щоб створити ScrollViewабо ListViewз maxHeight, вам просто потрібно створити навколо нього прозорий лінійний макет з висотою, якою ви хочете бути maxHeight. Потім ви встановлюєте висоту ScrollView на wrap_content. Це створює ScrollView, який, як видається, зростає, поки його висота не дорівнює батьківській LinearLayout.


3
Це було корисно для запобігання розширенню діалогу з прокручуваним вмістом на повну висоту екрана.
Кайл Іві

Невелика пропозиція буде використовувати FrameLayout замість LinearLayout, але я сумніваюся, що це має значення.
Кайл Іві

43
Якщо під переглядом прокрутки присутній якийсь макет, то цей трюк не буде спрацьовувати
Средху Мадху

2
ви можете, будь ласка, надати якийсь код? це не працювало для мене, тому, можливо, я роблю щось не так ...
андроїд розробник

не буде працювати, якщо у вас є кнопки під ним. це натисне кнопки з екрану
Лі Тянь Гонг

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>

Створення користувальницького перегляду, безумовно, найкращий спосіб досягти цього.
Бертрам Гілфойл

І це працює, якщо ви маєте макет нижче подання прокрутки! Ідеально!
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

Я б прокоментував відповідь свистуна, якби міг, але вважав корисним зазначити, що для того, щоб я вирішив цю проблему в контексті багатовіконного режиму в 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і це дозволило мені створити спеціальний діалог з a, ScrollViewоскільки дитина MaxHeightRelativeLayout, яка не розширює повну висоту екрана, а також скорочується, щоб розміститися в межах найменшого розміру вдови в мультивіконному для Android Н.


4

Немає можливості встановити maxHeight. Але Ви можете встановити Висоту.

Для цього вам потрібно буде виявити висоту кожного елемента, який ви прокручуєтеView. Після цього просто встановіть висоту scrollView на числоOfItens * 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

Оберніть 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>

1
Ідеальне рішення справді. Розумний і простий. Він підходить навіть для рециркуляції.
Алекс Белець

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"

Використання горизонтальної максимальної ширини зовсім однакове.


1

Ви спробували використовувати значення layout_weight ? Якщо встановити його на значення, що перевищує 0, воно розтягне цей погляд на інший доступний простір.

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

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

Більше інформації тут, переліченої у лінійному макеті.


1
Проблема з вагами полягає в тому, що вони відносні. Різні розміри екрана, різні результати, наприклад, з екраном 800 пікселів, я можу встановити вагу до певного значення, так що певна область закінчується потрібними 200 пікселями. Однак при екрані 850px певна площа в кінцевому підсумку перевищує 200px, але вкладені елементи все одно лише 200px. Ось чому я вважав за краще мати такий, maxHeightякий я можу встановити на певне значення опускання. (Я нарешті закінчився для обчислення та встановлення висот програмно)
znq

1

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


8
Ви не хочете встановлювати параметр "px". Цілком ймовірно, що ви не отримаєте бажаного результату на кількох пристроях. developer.android.com/guide/topics/resources/…
Hernd DerBeld

@HerndDerBeld ось так працює код. за бажанням ви завжди можете легко перетворити з DP у пікселі: плаваючі пікселі = TypedValue.applyDimension (TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources () .getDisplayMetrics ());
андроїд розробник

1

Як ми знаємо, пристрої під управлінням Android можуть мати різні розміри екрана. Як ми знаємо далі, погляди повинні динамічно коригуватись і ставати відповідним простором.

Якщо встановити максимальну висоту, можливо, ви змусите погляд не займати достатньо місця або займати менше місця. Я знаю, що іноді здається практично встановити максимальну висоту. Але якщо роздільна здатність коли-небудь різко зміниться, і вона стане !, то вид, що має максимальну висоту, буде виглядати не підходящим.

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

btw. minHeight не гарантується (і, можливо, не має існувати). це може мати певну користь, щоб змусити елементи бути видимими, тоді як інші відносні предмети стануть меншими.


6
Це неправильно. За цією логікою ви також не зможете сказати android: layout_width = "500dp".
Глен Мейнард

Я не бачу, що має бути неправильним, ні ваша логічна інтерпретація. Якщо ви встановите layout_width (що іноді нормально), це не гарантується. Можливо, 500dp виглядає на одному пристрої відповідним, на іншому - ні. Макет менеджери ftw! Можливо, ви могли б пояснити, що більше
прихильників

3
Так само справедливо сказати android: maxWidth = "500dp", як і Android: layout_width = "500dp". Вони обидва форсують певні розміри на вигляд.
Глен Мейнард

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

якщо ви, хлопці, хочете зробити перегляд прокрутки або перегляд, який не переповнюється, просто на RelativeLayout з видом зверху та знизу вгорі та внизу для нього:

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

Для цього потрібно більше кредиту. Конкретна, але проста реалізація.
Люк Еллісон

0

Я використовував користувальницький 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>
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.