Подтвердить что ты не робот

Как получить GridView, который адаптирует его высоту при добавлении элементов

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

Я могу показать эти строки "checkboxed" в строке. Моя проблема возникает, когда я позволяю пользователю динамически добавлять новые строки в GridView.

Я создал настраиваемый адаптер, который получает список строк. Скажем, у нас есть n строк. Адаптер возвращает "n + 1" для подсчета элементов; в getView он возвращает:

  • a Вид с LinearLayout, сам имеющий CheckBox и EditText для первых n элементов,
  • LinearLayout с простой кнопкой, с надписью "+" для элемента "n + 1".

Пока все хорошо. Когда нажимается кнопка "+" , я добавляю пустую строку в список строк и вызываю notifyDataSetChanged в адаптере.

GridView перерисовывает себя еще одним элементом. НО он сохраняет свою первоначальную высоту и создает вертикальную полосу прокрутки. Я бы хотел, чтобы GridView расширил свою высоту (т.е. Занимал больше места на экране и показывал все элементы).

Я попытался изменить экран на вертикальный LinearLayout вместо TableLayout, но результаты остались прежними.

Вот макет моего экрана:

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:scrollbars="none">
<LinearLayout
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    >

    <!-- other lines omitted -->

    <LinearLayout android:layout_width="fill_parent" 
                  android:layout_height="wrap_content" >
        <TextView
            android:layout_width="wrap_content" 
            android:layout_height="wrap_content"
            android:text="@string/wine_rack_explanation"
            android:layout_gravity="center_vertical" />
          <GridView
            android:layout_width="fill_parent" 
            android:layout_height="wrap_content"
            android:id="@+id/gvRack"
            android:columnWidth="90dp"    
            android:numColumns="auto_fit" />
    </LinearLayout>

<!-- other lines omitted -->

</LinearLayout>
</ScrollView>

Флажок + строковый элемент из адаптера определяется следующим образом:

<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="horizontal"

  android:layout_width="wrap_content"
  android:layout_height="wrap_content">
    <CheckBox android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:id="@+id/cbCoordinate"
              android:checked="true"
              />
    <EditText android:id="@+id/txtCoordinate"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content" />
</LinearLayout>

Элемент кнопки "+" определяется следующим образом:

<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="horizontal"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content">

    <Button android:id="@+id/btnAddBottle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/add_bottle_caption" />
</LinearLayout>

Я попытался вызвать invalidate или invalideViews в GridView после добавления элемента. Также называется invalidate на TableLayout и TableRow (в предыдущем макете экрана). Нет успеха.

Любая идея, почему GridView отказывается продлить свою высоту?

(Обратите внимание, что я полностью открыт для использования другой группы представлений, чем GridView)

4b9b3361

Ответ 1

Используйте этот код

public class MyGridView  extends GridView {

    public MyGridView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MyGridView(Context context) {
        super(context);
    }

    public MyGridView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
                MeasureSpec.AT_MOST);
        super.onMeasure(widthMeasureSpec, expandSpec);
    }
}

Ответ 2

Я сделал так:

Этот код установит высоту GridView по номеру Ребенка.

Примечание: Где 5 - количество столбцов.

private void setDynamicHeight(GridView gridView) {
        ListAdapter gridViewAdapter = gridView.getAdapter();
        if (gridViewAdapter == null) {
            // pre-condition
            return;
        }

        int totalHeight = 0;
        int items = gridViewAdapter.getCount();
        int rows = 0;

        View listItem = gridViewAdapter.getView(0, null, gridView);
        listItem.measure(0, 0);
        totalHeight = listItem.getMeasuredHeight();

        float x = 1;
        if( items > 5 ){
            x = items/5;
            rows = (int) (x + 1);
            totalHeight *= rows;
        }

        ViewGroup.LayoutParams params = gridView.getLayoutParams();
        params.height = totalHeight;
        gridView.setLayoutParams(params);
    }

Надеюсь, это поможет вам.

Ответ 3

Когда функция onMeasure() вызывается для GridView, если heightMode является MeasureSpec.UNSPECIFIED, то gridview будет таким же высоким, как и все содержащиеся в нем элементы (плюс некоторые дополнения).

Чтобы убедиться, что это так, вы можете сделать быстрый пользовательский вид, расширяющий GridView и включающий следующее переопределение:

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, MeasureSpec.UNSPECIFIED);
    }

Ответ 4

Это работает для меня:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/root"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/background" >

        <!-- MORE LAYOUTS IF YOU WANT -->

    <ScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_weight="1"
    android:fillViewport="true" >

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

                <!-- MORE LAYOUTS IF YOU WANT -->

       <GridView
            android:id="@+id/gridview"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_marginBottom="10dp"
            android:layout_marginLeft="20dp"
            android:layout_marginRight="20dp"
            android:layout_marginTop="5dp"
            android:gravity="center"
            android:horizontalSpacing="10dp"
            android:numColumns="auto_fit"
            android:stretchMode="columnWidth"
            android:verticalSpacing="10dp" >
       </GridView>

             <!-- MORE LAYOUTS IF YOU WANT -->

    </RelativeLayout>

    </ScrollView>

</RelativeLayout>

Ответ 5

Решение Грэма не помогло мне. Однако этот (с немного большим взломом) сделал: fooobar.com/questions/55012/...

Ответ 6

Это работает для меня

public class MyGridView extends GridView {
    public MyGridView(Context context) {
        super(context);
    }

    public MyGridView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

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

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        // set childs height to same value as child that has highest value
        for(int i=0; i<getChildCount(); i++) {
            MyLinearLayout child = (MyLinearLayout) getChildAt(i);
            AbsListView.LayoutParams params = (AbsListView.LayoutParams) child.getLayoutParams();
            params.height = MyLinearLayout.maxHeight;
            child.setLayoutParams(params);
        }

        // calculate total height and apply to the grid
        double numRow = Math.ceil((double) getCount() / (double) getNumColumns());
        LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) this.getLayoutParams();
        params.height = (int) numRow *  MyLinearLayout.maxHeight;
        this.setLayoutParams(params);

        // invalidate after change grid height
        this.invalidate();
    }
}

MyLinearLayout class

public class MyLinearLayout extends LinearLayout {
    public static int maxHeight = 0;

    public MyLinearLayout(Context context) {
        super(context);
    }

    public MyLinearLayout(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public MyLinearLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (maxHeight<this.getMeasuredHeight()) maxHeight=this.getMeasuredHeight();
    }
}

GridView содержит несколько дочерних элементов MyLinearLayout, и это макет

<?xml version="1.0" encoding="utf-8"?>
<com.mysystem.view.MyLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="100dp"
              android:layout_height="100dp"
              android:background="#ddd"
              android:padding="0.5dp"
              android:layout_gravity="top"
              android:gravity="center_horizontal"
              android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#fff"
        android:padding="20dp"
        android:orientation="vertical">

        <ImageView
            android:id="@+id/img_menu"
            android:layout_width="30dp"
            android:layout_gravity="center_horizontal"
            android:layout_height="30dp"
            android:layout_marginTop="5dp"/>

        <TextView
            android:id="@+id/tv_menu"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="5dp"
            android:textAlignment="center"
            android:textColor="#000"
            android:text="Title"
            android:textSize="10sp"/>

    </LinearLayout>
</com.mysystem.view.MyLinearLayout>

Ответ 7

Разработано на основе идеи, которую разделяет https://stackoverflow.com/users/4233197/hiren-patel, поэтому спасибо :)

Передайте вам GridView и его количество столбцов через эту функцию, и все готово.

private void setGridViewHeightBasedOnChildren(GridView gridView, int noOfColumns) {
        ListAdapter gridViewAdapter = gridView.getAdapter();
        if (gridViewAdapter == null) {
            // adapter is not set yet
            return;
        }

        int totalHeight; //total height to set on grid view
        int items = gridViewAdapter.getCount(); //no. of items in the grid
        int rows; //no. of rows in grid

        View listItem = gridViewAdapter.getView(0, null, gridView);
        listItem.measure(0, 0);
        totalHeight = listItem.getMeasuredHeight();

        float x;
        if( items > noOfColumns ){
            x = items/noOfColumns;

            //Check if exact no. of rows of rows are available, if not adding 1 extra row
            if(items%noOfColumns != 0) {
                rows = (int) (x + 1);
            }else {
                rows = (int) (x);
            }
            totalHeight *= rows;

            //Adding any vertical space set on grid view
            totalHeight += gridView.getVerticalSpacing() * rows;
        }

        //Setting height on grid view
        ViewGroup.LayoutParams params = gridView.getLayoutParams();
        params.height = totalHeight;
        gridView.setLayoutParams(params);
    }