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.