Как получить 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)
Ответы
Ответ 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);
}