j'essaye de placer une listview dans un listviewitem. la vue de liste intérieure ne doit pas être défilable mais prendre toute la taille dont elle a besoin pour afficher toutes ses lignes. existe-t-il une meilleure façon de procéder? table, grille, ...? le problème auquel je suis confronté en ce moment est que la vue de liste intérieure ne prend pas l'espace dont elle a besoin, elle est donc coupée à la fin du premier élément de liste. si j'essaie de faire défiler, juste la liste extérieure défile, ce qui est exactement ce que je veux.
merci, ma solution finale est
LinearLayout layout = (LinearLayout) row.findViewById(R.id.LLBroadcasts);
layout.removeAllViews();
for (Item b : bs.getItems()) {
View child = _inflater.inflate(R.layout.item_row, null);
TextView tvTitle = (TextView) child.findViewById(R.id.TVItemTitle);
tvTitle.setText(b.getTitle());
TextView tvDesc = (TextView) child.findViewById(R.id.TVItemDescription);
tvDesc.setText(b.getDescription());
layout.addView(child);
}
À partir de la Android - Listview : ListView est un groupe de vues qui affiche une liste d'éléments déroulants
Vous ne voulez pas vraiment faire défiler cette vue de liste intérieure, vous voulez faire défiler la vue de liste extérieure. Cependant, je suppose que la liste interne peut varier en fonction de la quantité d'éléments qu'elle contient.
Au lieu de la vue de liste interne, vous pouvez utiliser un
Pour la disposition linéaire (un exemple de code):
// access your linear layout
LinearLayout layout = (LinearLayout)findViewById(R.id.layout);
// load the xml structure of your row
View child = getLayoutInflater().inflate(R.layout.row);
// now fill the row as you would do with listview
//e.g. (TextView) child.findViewById(...
...
// and than add it
layout.addView(child);
Vous devez enregistrer la disposition linéaire dans un support de vue (voir Modèle de support de vue ). Je pense que la removeAllViews()
n'est nécessaire que lorsque la ligne actuelle a moins de lignes internes que celle réutilisée, donc je voudrais également enregistrer le nombre de lignes dans le support de vue.
Si le nombre maximal de lignes internes n'est pas trop élevé, vous pouvez également penser à les mettre en cache dans le support de vue pour éviter le gonflement et findByViewId (disons dans une liste de tableaux).
J'ai le même problème dans mon application, mais je devais utiliser un ListView car c'était un élément partagé et je ne voulais pas répliquer des composants égaux. Donc .. Je viens de fixer la taille de ListView interne par programme pour afficher toutes les lignes et .. le tour est joué! Problème résolu:
ViewGroup.LayoutParams layoutParams = innerListView.getLayoutParams();
layoutParams.height = (int) context.getResources().getDimension(R.dimen.rowheight) * innerListView.getCount();
innerListView.setLayoutParams(layoutParams);
CustomAdapter adapter = new CustomAdapter(context, blabla..);
innerListView.setAdapter(adapter);
rowListView.invalidate();
Peut-être que quelqu'un trouvera ma solution utile. Il est basé sur la réponse @ChrLipp et utilise LinearLayout.
public class NotScrollableListView extends LinearLayout {
private ListAdapter adapter;
private DataChangeObserver dataChangeObserver;
private Drawable divider;
private int dividerHeight;
private List<View> reusableViews = new ArrayList<>();
public NotScrollableListView(Context context) {
super(context);
}
public NotScrollableListView(Context context, AttributeSet attrs) {
super(context, attrs);
setAttributes(attrs);
}
public NotScrollableListView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setAttributes(attrs);
}
public ListAdapter getAdapter() {
return adapter;
}
public void setAdapter(ListAdapter adapter) {
if (this.adapter != null && dataChangeObserver != null) {
this.adapter.unregisterDataSetObserver(dataChangeObserver);
}
this.adapter = adapter;
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (adapter != null) {
dataChangeObserver = new DataChangeObserver();
adapter.registerDataSetObserver(dataChangeObserver);
fillContents();
}
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (adapter != null) {
adapter.unregisterDataSetObserver(dataChangeObserver);
dataChangeObserver = null;
}
}
private void fillContents() {
// clearing contents
this.removeAllViews();
final int count = adapter.getCount(); // item count
final int reusableCount = reusableViews.size(); // count of cached reusable views
// calculating of divider properties
ViewGroup.LayoutParams dividerLayoutParams = null;
if (divider != null && dividerHeight > 0) {
dividerLayoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, dividerHeight);
}
// adding items
for (int i = 0; i < count; i++) {
// adding item
View converView = null;
if (i < reusableCount) { // we have cached view
converView = reusableViews.get(i);
}
View view = adapter.getView(i, converView, this);
if (i >= reusableCount) { // caching view
reusableViews.add(view);
}
addView(view);
// adding divider
if (divider != null && dividerHeight > 0) {
if (i < count - 1) {
ImageView dividerView = new ImageView(getContext());
dividerView.setImageDrawable(divider);
dividerView.setLayoutParams(dividerLayoutParams);
addView(dividerView);
}
}
}
}
private void setAttributes(AttributeSet attributes) {
int[] dividerAttrs = new int[]{Android.R.attr.divider, Android.R.attr.dividerHeight};
TypedArray a = getContext().obtainStyledAttributes(attributes, dividerAttrs);
try {
divider = a.getDrawable(0);
dividerHeight = a.getDimensionPixelSize(1, 0);
} finally {
a.recycle();
}
setOrientation(VERTICAL);
}
private class DataChangeObserver extends DataSetObserver {
@Override
public void onChanged() {
super.onChanged();
fillContents();
}
@Override
public void onInvalidated() {
super.onInvalidated();
fillContents();
}
}
}
<com.sample.ui.view.NotScrollableListView
Android:id="@+id/internalList"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:divider="@color/list_divider_color"
Android:dividerHeight="@dimen/list_divider_width"
/>
J'ai essayé de créer cette structure exacte (un ListView
à l'intérieur d'un ListView
) et j'ai eu le même problème en ne montrant que le premier élément du ListView
intérieur. Je l'ai corrigé en changeant le layout_height
de la liste intérieure de match_parent
à un ensemble dp
.
Cela semblait fonctionner exactement comme je le voulais.
listView
à l'intérieur listView
Ou 2 listview
s dans le même activity
<com.example.taskgrptaskslistview.NestedListView
Android:id="@+id/listviewTasks"
Android:layout_width="0dip"
Android:layout_height="wrap_content"
Android:layout_marginBottom="2dp"
Android:layout_weight="1"
Android:cacheColorHint="#00000000" >
</com.example.taskgrptaskslistview.NestedListView>
</LinearLayout>
NestedListView:
import Android.content.Context;
import Android.util.AttributeSet;
import Android.view.MotionEvent;
import Android.view.View;
import Android.view.View.OnTouchListener;
import Android.view.ViewGroup;
import Android.widget.AbsListView;
import Android.widget.AbsListView.OnScrollListener;
import Android.widget.ListAdapter;
import Android.widget.ListView;
public class NestedListView extends ListView implements OnTouchListener, OnScrollListener {
private int listViewTouchAction;
private static final int MAXIMUM_LIST_ITEMS_VIEWABLE = 99;
public NestedListView(Context context, AttributeSet attrs) {
super(context, attrs);
listViewTouchAction = -1;
setOnScrollListener(this);
setOnTouchListener(this);
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
if (getAdapter() != null && getAdapter().getCount() > MAXIMUM_LIST_ITEMS_VIEWABLE) {
if (listViewTouchAction == MotionEvent.ACTION_MOVE) {
scrollBy(0, -1);
}
}
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int newHeight = 0;
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if (heightMode != MeasureSpec.EXACTLY) {
ListAdapter listAdapter = getAdapter();
if (listAdapter != null && !listAdapter.isEmpty()) {
int listPosition = 0;
for (listPosition = 0; listPosition < listAdapter.getCount()
&& listPosition < MAXIMUM_LIST_ITEMS_VIEWABLE; listPosition++) {
View listItem = listAdapter.getView(listPosition, null, this);
//now it will not throw a NPE if listItem is a ViewGroup instance
if (listItem instanceof ViewGroup) {
listItem.setLayoutParams(new LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
}
listItem.measure(widthMeasureSpec, heightMeasureSpec);
newHeight += listItem.getMeasuredHeight();
}
newHeight += getDividerHeight() * listPosition;
}
if ((heightMode == MeasureSpec.AT_MOST) && (newHeight > heightSize)) {
if (newHeight > heightSize) {
newHeight = heightSize;
}
}
} else {
newHeight = getMeasuredHeight();
}
setMeasuredDimension(getMeasuredWidth(), newHeight);
}
@Override
public boolean onTouch(View v, MotionEvent event) {
if (getAdapter() != null && getAdapter().getCount() > MAXIMUM_LIST_ITEMS_VIEWABLE) {
if (listViewTouchAction == MotionEvent.ACTION_MOVE) {
scrollBy(0, 1);
}
}
return false;
}
}