Comment mettre un ListView dans un ScrollView sans qu'il s'effondre?
j'ai cherché des solutions à ce problème, et la seule réponse que je puisse trouver semble être " ne mettez pas de ListView dans un ScrollView ". Je n'ai pas encore vu d'explication réelle pour pourquoi cependant. La seule raison pour laquelle je peux sembler de trouver est que Google ne pense pas que vous devriez vouloir faire cela. Eh bien, je ne, je l'ai fait.
donc la question est, comment pouvez-vous placer un ListView dans un ScrollView sans qu'il s'effondre à son hauteur minimale?
27 réponses
utiliser un ListView
pour le faire ne pas faire défiler est extrêmement coûteux et va à l'encontre de l'ensemble de l'objectif de ListView
. Vous devriez et non . Il suffit d'utiliser un LinearLayout
à la place.
voici ma solution. Je suis assez nouveau sur la plateforme Android, et je suis sûr que c'est un peu hackish, surtout dans la partie sur les appels .mesurer directement, et définir la propriété LayoutParams.height
directement, mais cela fonctionne.
Tout ce que vous avez à faire est d'appeler Utility.setListViewHeightBasedOnChildren(yourListView)
et il sera redimensionné pour accommoder exactement la hauteur de ses articles.
public class Utility {
public static void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null) {
// pre-condition
return;
}
int totalHeight = listView.getPaddingTop() + listView.getPaddingBottom();
for (int i = 0; i < listAdapter.getCount(); i++) {
View listItem = listAdapter.getView(i, null, listView);
if (listItem instanceof ViewGroup) {
listItem.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
}
listItem.measure(0, 0);
totalHeight += listItem.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
}
}
Ce sera certainement le travail............
Vous devez juste remplacer votre <ScrollView ></ScrollView>
dans le fichier de mise en page XML avec ce Custom ScrollView
comme <com.tmd.utils.VerticalScrollview > </com.tmd.utils.VerticalScrollview >
package com.tmd.utils;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.ScrollView;
public class VerticalScrollview extends ScrollView{
public VerticalScrollview(Context context) {
super(context);
}
public VerticalScrollview(Context context, AttributeSet attrs) {
super(context, attrs);
}
public VerticalScrollview(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
switch (action)
{
case MotionEvent.ACTION_DOWN:
Log.i("VerticalScrollview", "onInterceptTouchEvent: DOWN super false" );
super.onTouchEvent(ev);
break;
case MotionEvent.ACTION_MOVE:
return false; // redirect MotionEvents to ourself
case MotionEvent.ACTION_CANCEL:
Log.i("VerticalScrollview", "onInterceptTouchEvent: CANCEL super false" );
super.onTouchEvent(ev);
break;
case MotionEvent.ACTION_UP:
Log.i("VerticalScrollview", "onInterceptTouchEvent: UP super false" );
return false;
default: Log.i("VerticalScrollview", "onInterceptTouchEvent: " + action ); break;
}
return false;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
super.onTouchEvent(ev);
Log.i("VerticalScrollview", "onTouchEvent. action: " + ev.getAction() );
return true;
}
}
inscrit de mettre ListView
dans un ScrollView
, nous pouvons utiliser ListView
comme un ScrollView
. Les choses qui doivent être dans ListView
peuvent être mis à l'intérieur du ListView
. D'autres layouts en haut et en bas de ListView
peuvent être mis en ajoutant des layouts à l'en-tête et au pied de page de ListView
. Ainsi, le ListView
entier vous donnera une expérience de défilement .
Il y a beaucoup de choses des situations où il fait beaucoup de sens d'avoir de ListView dans un ScrollView.
voici le code basé sur la suggestion de DougW... travaille dans un fragment, prend moins de mémoire.
public static void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null) {
return;
}
int desiredWidth = MeasureSpec.makeMeasureSpec(listView.getWidth(), MeasureSpec.AT_MOST);
int totalHeight = 0;
View view = null;
for (int i = 0; i < listAdapter.getCount(); i++) {
view = listAdapter.getView(i, view, listView);
if (i == 0) {
view.setLayoutParams(new ViewGroup.LayoutParams(desiredWidth, LayoutParams.WRAP_CONTENT));
}
view.measure(desiredWidth, MeasureSpec.UNSPECIFIED);
totalHeight += view.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
listView.requestLayout();
}
call setListViewHeightBasedOnChildren(listview) sur chaque listview intégré.
ListView est en fait déjà capable de se mesurer pour être assez grand pour afficher tous les articles, mais il ne le fait pas quand vous spécifiez simplement wrap_content (MeasureSpec.INDÉTERMINÉ.) Il le fera si on lui donne une hauteur avec MeasureSpec.Presque. Avec cette connaissance, vous pouvez créer une sous-classe très simple pour résoudre ce problème qui fonctionne beaucoup mieux que n'importe laquelle des solutions affichées ci-dessus. Vous devez toujours utiliser wrap_content avec cette sous-classe.
public class ListViewForEmbeddingInScrollView extends ListView {
public ListViewForEmbeddingInScrollView(Context context) {
super(context);
}
public ListViewForEmbeddingInScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ListViewForEmbeddingInScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 4, MeasureSpec.AT_MOST));
}
}
la Manipulation de la heightMeasureSpec être AT_MOST avec une très grande taille (Entier.MAX_VALUE >> 4) fait que le ListView mesure tous ses enfants jusqu'à la hauteur donnée (très grande) et règle sa hauteur en conséquence.
Cela fonctionne mieux que les autres solutions pour quelques raisons:
- Il mesure tout correctement (rembourrage, intercalaires)
- à la mesure de la ListView au cours de la mesure pass
- en raison de #2, il gère correctement les changements de largeur ou de nombre d'articles sans aucun code supplémentaire
du côté négatif, vous pourriez soutenir que faire cela dépend d'un comportement non documenté dans le SDK qui pourrait changer. D'un autre côté, vous pourriez argumenter que c'est ainsi que wrap_content devrait fonctionner avec ListView et que le comportement wrap_content actuel est juste cassé.
Si vous êtes inquiet que le comportement pourrait changer à l'avenir, vous devrez simplement copier la fonction onMeasure et les fonctions connexes à partir de ListView.java et dans votre propre sous-classe, puis faire le chemin AT_MOST through onMeasure Exécuter pour UNSPECIFIED aussi bien.
Par ailleurs, je crois que c'est parfaitement valable lorsque vous travaillez avec de petits nombres d'éléments de la liste. Il peut être inefficace par rapport à LinearLayout, mais lorsque le nombre d'articles est faible, L'utilisation de LinearLayout est l'optimisation inutile et donc complexité inutile.
il y a un cadre intégré pour cela. Sur le ScrollView:
android:fillViewport="true"
En Java,
mScrollView.setFillViewport(true);
Romain Guy l'explique en profondeur ici: http://www.curious-creature.org/2010/08/15/scrollviews-handy-trick/
nous ne pouvions pas utiliser deux défilement simultanément.Nous aurons obtenir la longueur totale de ListView et étendre listview avec la hauteur totale .Ensuite, nous pouvons ajouter ListView dans ScrollView directement ou en utilisant LinearLayout parce que ScrollView ont directement un enfant . copiez la méthode setListViewHeightBasedOnChildren(lv) dans votre code et développez listview puis vous pouvez utiliser listview à l'intérieur de scrollview. \layout fichier xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ScrollView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#1D1D1D"
android:orientation="vertical"
android:scrollbars="none" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#1D1D1D"
android:orientation="vertical" >
<TextView
android:layout_width="fill_parent"
android:layout_height="40dip"
android:background="#333"
android:gravity="center_vertical"
android:paddingLeft="8dip"
android:text="First ListView"
android:textColor="#C7C7C7"
android:textSize="20sp" />
<ListView
android:id="@+id/first_listview"
android:layout_width="260dp"
android:layout_height="wrap_content"
android:divider="#00000000"
android:listSelector="#ff0000"
android:scrollbars="none" />
<TextView
android:layout_width="fill_parent"
android:layout_height="40dip"
android:background="#333"
android:gravity="center_vertical"
android:paddingLeft="8dip"
android:text="Second ListView"
android:textColor="#C7C7C7"
android:textSize="20sp" />
<ListView
android:id="@+id/secondList"
android:layout_width="260dp"
android:layout_height="wrap_content"
android:divider="#00000000"
android:listSelector="#ffcc00"
android:scrollbars="none" />
</LinearLayout>
</ScrollView>
</LinearLayout>
méthode onCreate dans la classe D'activité:
import java.util.ArrayList;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListAdapter;
import android.widget.ListView;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.listview_inside_scrollview);
ListView list_first=(ListView) findViewById(R.id.first_listview);
ListView list_second=(ListView) findViewById(R.id.secondList);
ArrayList<String> list=new ArrayList<String>();
for(int x=0;x<30;x++)
{
list.add("Item "+x);
}
ArrayAdapter<String> adapter=new ArrayAdapter<String>(getApplicationContext(),
android.R.layout.simple_list_item_1,list);
list_first.setAdapter(adapter);
setListViewHeightBasedOnChildren(list_first);
list_second.setAdapter(adapter);
setListViewHeightBasedOnChildren(list_second);
}
public static void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null) {
// pre-condition
return;
}
int totalHeight = 0;
for (int i = 0; i < listAdapter.getCount(); i++) {
View listItem = listAdapter.getView(i, null, listView);
listItem.measure(0, 0);
totalHeight += listItem.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight
+ (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
}
vous créez ListView personnalisé qui est non Scrollable
public class NonScrollListView extends ListView {
public NonScrollListView(Context context) {
super(context);
}
public NonScrollListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public NonScrollListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int heightMeasureSpec_custom = MeasureSpec.makeMeasureSpec(
Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, heightMeasureSpec_custom);
ViewGroup.LayoutParams params = getLayoutParams();
params.height = getMeasuredHeight();
}
}
Dans Votre Fichier De Ressources De Mise En Page
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<!-- com.Example Changed with your Package name -->
<com.Example.NonScrollListView
android:id="@+id/lv_nonscroll_list"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</com.Example.NonScrollListView>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/lv_nonscroll_list" >
<!-- Your another layout in scroll view -->
</RelativeLayout>
</RelativeLayout>
Dans Le Fichier Java
créez un objet de votre customListview au lieu de ListView comme : Nonscrollllistview non_scroll_list = (Nonscrollistview) findViewById (R. id.lv_nonscroll_list);
il s'agit d'une combinaison des réponses de DougW, Good Guy Greg, et Paul. J'ai trouvé qu'il était tout nécessaire en essayant d'utiliser ceci avec un adaptateur listview personnalisé et des éléments de liste non standard sinon le listview a écrasé l'application (également écrasé avec la réponse par Nex):
public void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null) {
return;
}
int totalHeight = listView.getPaddingTop() + listView.getPaddingBottom();
for (int i = 0; i < listAdapter.getCount(); i++) {
View listItem = listAdapter.getView(i, null, listView);
if (listItem instanceof ViewGroup)
listItem.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
listItem.measure(0, 0);
totalHeight += listItem.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
}
j'ai converti le Utility
de @DougW en C# (Utilisé En Xamarin). Ce qui suit fonctionne bien pour les articles de hauteur fixe dans la liste, et va être la plupart du temps très bien, ou au moins un bon début, si seulement certains des éléments sont un peu plus grand que l'article standard.
// You will need to put this Utility class into a code file including various
// libraries, I found that I needed at least System, Linq, Android.Views and
// Android.Widget.
using System;
using System.Linq;
using Android.Views;
using Android.Widget;
namespace UtilityNamespace // whatever you like, obviously!
{
public class Utility
{
public static void setListViewHeightBasedOnChildren (ListView listView)
{
if (listView.Adapter == null) {
// pre-condition
return;
}
int totalHeight = listView.PaddingTop + listView.PaddingBottom;
for (int i = 0; i < listView.Count; i++) {
View listItem = listView.Adapter.GetView (i, null, listView);
if (listItem.GetType () == typeof(ViewGroup)) {
listItem.LayoutParameters = new LinearLayout.LayoutParams (ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.WrapContent);
}
listItem.Measure (0, 0);
totalHeight += listItem.MeasuredHeight;
}
listView.LayoutParameters.Height = totalHeight + (listView.DividerHeight * (listView.Count - 1));
}
}
}
Merci @DougW, cela m'a sorti d'une situation difficile quand j'ai dû travailler avec le code D'autres personnes. :- )
vous ne devez pas mettre un ListView dans un ScrollView car un ListView déjà est un ScrollView. Donc, ce serait comme mettre un ScrollView dans un ScrollView.
Qu'essayez-vous d'accomplir?
hey, j'ai eu un problème similaire. Je voulais afficher une vue de liste qui ne défilait pas et j'ai trouvé que la manipulation des paramètres fonctionnait mais était inefficace et se comporterait différemment sur différents appareils.. en conséquence, il s'agit d'un élément de mon programme qui fait cela très efficacement.
db = new dbhelper(this);
cursor = db.dbCursor();
int count = cursor.getCount();
if (count > 0)
{
LinearLayout linearLayout = (LinearLayout) findViewById(R.id.layoutId);
startManagingCursor(YOUR_CURSOR);
YOUR_ADAPTER(**or SimpleCursorAdapter **) adapter = new YOUR_ADAPTER(this,
R.layout.itemLayout, cursor, arrayOrWhatever, R.id.textViewId,
this.getApplication());
int i;
for (i = 0; i < count; i++){
View listItem = adapter.getView(i,null,null);
linearLayout.addView(listItem);
}
}
Note: Si vous utilisez ceci, notifyDataSetChanged();
ne fonctionnera pas comme prévu car les vues ne seront pas redessinées.
Faire cela que si vous avez besoin d'un travail autour de
adapter.registerDataSetObserver(new DataSetObserver() {
@Override
public void onChanged() {
super.onChanged();
removeAndRedrawViews();
}
});
il y a deux problèmes lors de l'utilisation d'un ListView à l'intérieur d'un ScrollView.
1 - ListView doit atteindre la hauteur de ses enfants. cette liste résoudre ce problème:
public class ListViewExpanded extends ListView
{
public ListViewExpanded(Context context, AttributeSet attrs)
{
super(context, attrs);
setDividerHeight(0);
}
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST));
}
}
la hauteur du diviseur doit être 0, utilisez le rembourrage dans les rangées à la place.
2 - le ListView consomme des événements tactiles donc ScrollView ne peut pas être scrollé comme d'habitude. Cette ScrollView résoudre ce problème:
public class ScrollViewInterceptor extends ScrollView
{
float startY;
public ScrollViewInterceptor(Context context, AttributeSet attrs)
{
super(context, attrs);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent e)
{
onTouchEvent(e);
if (e.getAction() == MotionEvent.ACTION_DOWN) startY = e.getY();
return (e.getAction() == MotionEvent.ACTION_MOVE) && (Math.abs(startY - e.getY()) > 50);
}
}
C'est le meilleur moyen que j'ai trouvé faire l'affaire!
C'est la seule chose qui a fonctionné pour moi:
à partir de Lollipop, vous pouvez utiliser
yourtListView.setNestedScrollingEnabled(true);
ceci active ou désactive le défilement emboîté pour cette vue si vous avez besoin d'une rétrocompatibilité avec l'ancienne version de L'OS, vous devrez utiliser le RecyclerView.
grâce à Vinay code voici mon code pour quand vous ne pouvez pas avoir une liste à l'intérieur d'un scrollview pourtant vous besoin de quelque chose comme ça
LayoutInflater li = LayoutInflater.from(this);
RelativeLayout parent = (RelativeLayout) this.findViewById(R.id.relativeLayoutCliente);
int recent = 0;
for(Contatto contatto : contatti)
{
View inflated_layout = li.inflate(R.layout.header_listview_contatti, layout, false);
inflated_layout.setId(contatto.getId());
((TextView)inflated_layout.findViewById(R.id.textViewDescrizione)).setText(contatto.getDescrizione());
((TextView)inflated_layout.findViewById(R.id.textViewIndirizzo)).setText(contatto.getIndirizzo());
((TextView)inflated_layout.findViewById(R.id.textViewTelefono)).setText(contatto.getTelefono());
((TextView)inflated_layout.findViewById(R.id.textViewMobile)).setText(contatto.getMobile());
((TextView)inflated_layout.findViewById(R.id.textViewFax)).setText(contatto.getFax());
((TextView)inflated_layout.findViewById(R.id.textViewEmail)).setText(contatto.getEmail());
RelativeLayout.LayoutParams relativeParams = new RelativeLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
if (recent == 0)
{
relativeParams.addRule(RelativeLayout.BELOW, R.id.headerListViewContatti);
}
else
{
relativeParams.addRule(RelativeLayout.BELOW, recent);
}
recent = inflated_layout.getId();
inflated_layout.setLayoutParams(relativeParams);
//inflated_layout.setLayoutParams( new RelativeLayout.LayoutParams(source));
parent.addView(inflated_layout);
}
le relativeLayout reste à l'intérieur d'un ScrollView de sorte qu'il devient de défilement :)
Voici une petite modification sur @djunod 's réponse que je dois le faire fonctionner parfaitement:
public static void setListViewHeightBasedOnChildren(ListView listView)
{
ListAdapter listAdapter = listView.getAdapter();
if(listAdapter == null) return;
if(listAdapter.getCount() <= 1) return;
int desiredWidth = MeasureSpec.makeMeasureSpec(listView.getWidth(), MeasureSpec.AT_MOST);
int totalHeight = 0;
View view = null;
for(int i = 0; i < listAdapter.getCount(); i++)
{
view = listAdapter.getView(i, view, listView);
view.measure(desiredWidth, MeasureSpec.UNSPECIFIED);
totalHeight += view.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
listView.requestLayout();
}
essayez ceci, cela fonctionne pour moi, j'ai oublié où je l'ai trouvé, quelque part dans le débordement de pile, Je ne suis pas ici pour expliquer pourquoi cela ne fonctionne pas, Mais voici la réponse :).
final ListView AturIsiPulsaDataIsiPulsa = (ListView) findViewById(R.id.listAturIsiPulsaDataIsiPulsa);
AturIsiPulsaDataIsiPulsa.setOnTouchListener(new ListView.OnTouchListener()
{
@Override
public boolean onTouch(View v, MotionEvent event)
{
int action = event.getAction();
switch (action)
{
case MotionEvent.ACTION_DOWN:
// Disallow ScrollView to intercept touch events.
v.getParent().requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_UP:
// Allow ScrollView to intercept touch events.
v.getParent().requestDisallowInterceptTouchEvent(false);
break;
}
// Handle ListView touch events.
v.onTouchEvent(event);
return true;
}
});
AturIsiPulsaDataIsiPulsa.setClickable(true);
AturIsiPulsaDataIsiPulsa.setAdapter(AturIsiPulsaDataIsiPulsaAdapter);
EDIT ! J'ai enfin trouvé où j'ai obtenu le code. ici ! : ListView à l'intérieur de ScrollView n'est pas le défilement sur Android
bien que les méthodes suggérées setListViewHeightBasedOnChildren () fonctionnent dans la plupart des cas, dans certains cas, spécialement avec beaucoup d'articles, j'ai remarqué que les derniers éléments ne sont pas affichés. J'ai donc décidé d'imiter une version simple du comportement ListView afin de réutiliser n'importe quel code Adaptateur, voici L'alternative ListView:
import android.content.Context;
import android.database.DataSetObserver;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.ListAdapter;
public class StretchedListView extends LinearLayout {
private final DataSetObserver dataSetObserver;
private ListAdapter adapter;
private OnItemClickListener onItemClickListener;
public StretchedListView(Context context, AttributeSet attrs) {
super(context, attrs);
setOrientation(LinearLayout.VERTICAL);
this.dataSetObserver = new DataSetObserver() {
@Override
public void onChanged() {
syncDataFromAdapter();
super.onChanged();
}
@Override
public void onInvalidated() {
syncDataFromAdapter();
super.onInvalidated();
}
};
}
public void setAdapter(ListAdapter adapter) {
ensureDataSetObserverIsUnregistered();
this.adapter = adapter;
if (this.adapter != null) {
this.adapter.registerDataSetObserver(dataSetObserver);
}
syncDataFromAdapter();
}
protected void ensureDataSetObserverIsUnregistered() {
if (this.adapter != null) {
this.adapter.unregisterDataSetObserver(dataSetObserver);
}
}
public Object getItemAtPosition(int position) {
return adapter != null ? adapter.getItem(position) : null;
}
public void setSelection(int i) {
getChildAt(i).setSelected(true);
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
public ListAdapter getAdapter() {
return adapter;
}
public int getCount() {
return adapter != null ? adapter.getCount() : 0;
}
private void syncDataFromAdapter() {
removeAllViews();
if (adapter != null) {
int count = adapter.getCount();
for (int i = 0; i < count; i++) {
View view = adapter.getView(i, null, this);
boolean enabled = adapter.isEnabled(i);
if (enabled) {
final int position = i;
final long id = adapter.getItemId(position);
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (onItemClickListener != null) {
onItemClickListener.onItemClick(null, v, position, id);
}
}
});
}
addView(view);
}
}
}
}
une solution que j'utilise est d'ajouter tout le contenu de ScrollView (ce qui devrait être au-dessus et sous listView) comme headerView et footerView dans ListView.
donc cela fonctionne comme, aussi convertview est resued comment il devrait être.
Toutes ces réponses sont fausses!!! Si vous essayez de mettre un listview dans une vue scroll, vous devriez repenser votre conception. Vous essayez de mettre un ScrollView dans un ScrollView. Interférer avec la liste nuira à la performance de la liste. Il a été conçu pour être comme ça par Androïde.
si vous voulez vraiment que la liste soit dans le même rouleau que les autres éléments, tout ce que vous avez à faire est d'ajouter les autres éléments dans le haut de la liste en utilisant un simple switch statement dans votre adaptateur:
class MyAdapter extends ArrayAdapter{
public MyAdapter(Context context, int resource, List objects) {
super(context, resource, objects);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewItem viewType = getItem(position);
switch(viewType.type){
case TEXTVIEW:
convertView = layouteInflater.inflate(R.layout.textView1, parent, false);
break;
case LISTITEM:
convertView = layouteInflater.inflate(R.layout.listItem, parent, false);
break; }
return convertView;
}
}
l'adaptateur de liste peut tout gérer puisqu'il ne rend que ce qui est visible.
avant c'était impossible. Mais avec la sortie de nouvelles bibliothèques Appcompat et Design libraries, cela est possible.
vous avez juste à utiliser NestedScrollView https://developer.android.com/reference/android/support/v4/widget/NestedScrollView.html
Je ne sais pas s'il fonctionnera avec Listview ou non, mais il fonctionne avec RecyclerView.
Extrait De Code:
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.v4.widget.NestedScrollView>
Tout ce problème disparaîtrait si LinearLayout avait une méthode setAdapter, parce que quand vous avez dit à quelqu'un de l'utiliser à la place, l'alternative serait triviale.
si vous voulez réellement un ListView défilant dans une autre vue défilante, cela ne vous aidera pas, mais sinon cela vous donnera au moins une idée.
vous devez créer un adaptateur personnalisé pour combiner tout le contenu que vous voulez faire défiler et mettre l'adaptateur de ListView à que.
Je n'ai pas de code d'exemple à portée de main, mais si vous voulez quelque chose comme.
<ListView/>
(other content)
<ListView/>
ensuite, vous devez créer un adaptateur qui représente tout ce contenu. Les ListView / adaptateurs sont assez intelligents pour prendre en charge différents types, mais vous devez écrire vous-même l'adaptateur.
L'API Android UI N'est tout simplement pas aussi mature que presque tout le reste là-bas, donc il n'a pas les mêmes subtilités que les autres plates-formes. En outre, lorsque vous faites quelque chose sur android vous devez être dans un État d'esprit android (unix) où vous vous attendez à ce que pour faire quoi que ce soit, vous allez probablement avoir à assembler des fonctionnalités de plus petites pièces et d'écrire un tas de votre propre code pour le faire fonctionner.
Lorsque nous place ListView
à l'intérieur ScrollView
deux problèmes se posent. L'un est ScrollView
mesure ses enfants en mode non spécifié, donc ListView
fixe sa propre taille pour accommoder un seul article(Je ne sais pas pourquoi), un autre est ScrollView
intercepte l'événement touch de sorte que ListView
ne défile pas.
mais nous can place ListView
à l'intérieur ScrollView
avec quelques contournements. Ce post , par moi, explique la solution de contournement. Par cette solution, nous pouvons également conserver une ListView
fonction de recyclage.
au lieu de placer listview dans Scrollview, placez le reste du contenu entre listview et l'ouverture de Scrollview comme une vue séparée et définissez cette vue comme l'en-tête de listview. Ainsi, vous finirez finalement par ne voir que la liste prise en charge de Scroll.
cette bibliothèque est la solution la plus facile et la plus rapide au problème.
voici ma version du code qui calcule la hauteur totale de la vue Liste. Celui-ci travaille pour moi:
public static void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null || listAdapter.getCount() < 2) {
// pre-condition
return;
}
int totalHeight = 0;
int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(BCTDApp.getDisplaySize().width, View.MeasureSpec.AT_MOST);
int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
for (int i = 0; i < listAdapter.getCount(); i++) {
View listItem = listAdapter.getView(i, null, listView);
if (listItem instanceof ViewGroup) listItem.setLayoutParams(lp);
listItem.measure(widthMeasureSpec, heightMeasureSpec);
totalHeight += listItem.getMeasuredHeight();
}
totalHeight += listView.getPaddingTop() + listView.getPaddingBottom();
totalHeight += (listView.getDividerHeight() * (listAdapter.getCount() - 1));
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight;
listView.setLayoutParams(params);
listView.requestLayout();
}