J'essaie d'afficher une liste de chaînes de plus en plus dynamique avec une case à cocher dans un GridView, lui-même dans un TableLayout.
Je peux afficher ces chaînes "cochées" bien dans une rangée. Mon problème survient lorsque je laisse l'utilisateur ajouter dynamiquement de nouvelles chaînes dans GridView.
J'ai créé un adaptateur personnalisé qui reçoit la liste des chaînes. Disons que nous avons n chaînes. L'adaptateur renvoie 'n + 1' pour le nombre d'éléments. Dans getView, il retourne:
Jusqu'ici tout va bien. Lorsque le bouton '+' est cliqué, j'ajoute une chaîne vide à la liste des chaînes et appelle notifyDataSetChanged dans l'adaptateur.
Le GridView se redessine avec un élément supplémentaire. MAIS il garde sa hauteur d'origine et crée une barre de défilement verticale. J'aimerais que le GridView augmente sa hauteur (c'est-à-dire qu'il prenne plus de place à l'écran et affiche tous les éléments).
J'ai essayé de changer l'écran en LinearLayout vertical au lieu de TableLayout, mais les résultats sont les mêmes.
Voici la disposition de mon écran:
<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>
La case à cocher + élément de chaîne de l'adaptateur est définie comme suit:
<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>
Le bouton «+» est défini comme suit:
<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>
J'ai essayé d'appeler invalidate ou invalideViews sur GridView après l'ajout d'un élément. Aussi appelé invalider sur TableLayout et TableRow (dans la disposition précédente de l'écran). Sans succès.
Aucune idée pourquoi le GridView refuse d'étendre sa hauteur?
(Notez que je suis tout à fait disposé à utiliser un autre groupe de vues que le GridView)
Utilisez ce code
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);
}
}
J'ai fait comme ça:
Ce code définira GridView
height selon nombre de enfant .
Remarque: Où 5
est le nombre de colonnes.
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);
}
J'espère que ceci vous aidera.
Lorsque onMeasure () est appelé pour GridView, si heightMode est MeasureSpec.UNSPECIFIED, la vue grille sera aussi grande que tous ses éléments contenus (plus un remplissage).
Pour vous assurer que c'est le cas, vous pouvez créer une vue personnalisée rapide étendant GridView et incluant le remplacement suivant:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, MeasureSpec.UNSPECIFIED);
}
Cela fonctionne pour moi:
<?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>
La solution de Graham n'a pas fonctionné pour moi. Cependant celui-ci (avec un peu plus de piratage) a: https://stackoverflow.com/a/8483078/479478
Cela fonctionne pour moi
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's height
this.invalidate();
}
}
Classe MyLinearLayout
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();
}
}
Le GridView contient des enfants de MyLinearLayout, et voici la disposition
<?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>