web-dev-qa-db-fra.com

Comment masquer un élément dans une liste dans Android

Je sais, cette question a déjà été posée, mais je n'ai pas trouvé de réponse satisfaisante à cette question.

Est-il possible de cacher certains éléments dans une ListView sans modifier les données source?

J'ai essayé de régler la visibilité de la vue d'élément sur disparu, elle ne sera plus affichée, mais la place réservée à cet élément est toujours là.

J'ai aussi mis:

Android:dividerHeight="0dp"
Android:divider="#FFFFFF"

Sans succès.

22
Tima

Vous pouvez écrire votre propre variable ListAdapter ou une des sous-classes existantes.

Dans votre ListAdapter, vous filtreriez simplement les éléments que vous ne voulez pas afficher en renvoyant les valeurs modifiées pour getCount(), getItem() et getItemId() selon le cas.

20
Carsten

J'ai essayé plusieurs solutions, y compris setVisibitlity(View.GONE) et en gonflant une vue null par défaut, mais toutes ont un problème commun et les séparateurs entre les éléments masqués sont empilés et créent un mauvais espace gris visible dans les grandes listes.

Si votre ListView est soutenu par un CursorAdapter, la meilleure solution consiste à l'envelopper avec un CursorWrapper.

Donc ma solution (basée sur la réponse @RomanUsachev ici ) est la suivante:

FilterCursorWrapper

   public class FilterCursorWrapper extends CursorWrapper {
    private int[] index;
    private int count = 0;
    private int pos = 0;

    public boolean isHidden(String path) {

      // the logic to check where this item should be hidden

      //   if (some condintion)
      //      return false;
      //    else {
      //       return true; 
      //   }

       return false;

    }

    public FilterCursorWrapper(Cursor cursor, boolean doFilter, int column) {
        super(cursor);
        if (doFilter) {
            this.count = super.getCount();
            this.index = new int[this.count];
            for (int i = 0; i < this.count; i++) {
                super.moveToPosition(i);
                if (!isHidden(this.getString(column)))
                    this.index[this.pos++] = i;
            }
            this.count = this.pos;
            this.pos = 0;
            super.moveToFirst();
        } else {
            this.count = super.getCount();
            this.index = new int[this.count];
            for (int i = 0; i < this.count; i++) {
                this.index[i] = i;
            }
        }
    }

    @Override
    public boolean move(int offset) {
        return this.moveToPosition(this.pos + offset);
    }

    @Override
    public boolean moveToNext() {
        return this.moveToPosition(this.pos + 1);
    }

    @Override
    public boolean moveToPrevious() {
        return this.moveToPosition(this.pos - 1);
    }

    @Override
    public boolean moveToFirst() {
        return this.moveToPosition(0);
    }

    @Override
    public boolean moveToLast() {
        return this.moveToPosition(this.count - 1);
    }

    @Override
    public boolean moveToPosition(int position) {
        if (position >= this.count || position < 0)
            return false;
        return super.moveToPosition(this.index[position]);
    }

    @Override
    public int getCount() {
        return this.count;
    }

    @Override
    public int getPosition() {
        return this.pos;
    }
}

lorsque votre Cursor est prête, passez à FilterCursorWrapper avec l'index de colonne souhaité.

FilterCursorWrapper filterCursorWrapper = new FilterCursorWrapper(cursor, true,DATA_COLUMN_INDEX);

dataAdapter.changeCursor(filterCursorWrapper);

et si vous filtrez et triez, n'oubliez pas d'utiliser FilterCursorWrapper partout:

    dataAdapter.setFilterQueryProvider(new FilterQueryProvider() {
        @Override
        public Cursor runQuery(CharSequence constraint) {
            String selection = MediaStore.Video.Media.DATA + " LIKE '%" + constraint.toString().toLowerCase() + "%'";
            return new FilterCursorWrapper(context.getContentResolver().query(videoMediaUri, columns, selection, null, null), true, DATA_COLUMN_INDEX);
        }
    });

et pour rafraîchir la liste, cela suffit pour interroger avec un filtre vide:

dataAdapter.getFilter().filter("");

et vous avez terminé, en changeant simplement la logique de la méthode isHidden, vous contrôlez l’affichage ou le masquage des éléments masqués. Et l'avantage est que vous ne voyez pas les séparateurs indésirables empilés. :-)

11
Mohsen Afshin

si vous voulez masquer l'élément comme ceci:

convertView.setLayoutParams(new AbsListView.LayoutParams(-1,1));
convertView.setVisibility(View.GONE);

ne peut pas être AbsListView.LayoutParams (-1,0);

si convertview est réutilisé, vous devriez ajouter ceci ci-dessous pour le régler en hauteur:

if(convertView.getVisibility() == View.GONE) {
            convertView.setVisibility(View.VISIBLE);
            convertView.setLayoutParams(new AbsListView.LayoutParams(-1,-2));
        }
9
taotao

Dans certains cas, vous avez une solution simple:

Je dois masquer une vue dans une vue de liste car les éléments à remplir pour afficher la vue sont invalides

Dans mon adaptateur de liste:

public class PlanListAdapter extends BaseAdapter{

//some code here : constructor ......

    // my code that create the view from the item list (one view by item ...)
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {


        LayoutInflater inflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        convertView = inflater.inflate(R.layout.my_layout, null);

        if(my_data_are_not_valid) {
             //just create an empty view     
             convertView = new Space(context);  
        }
        else {
             //populate the view with data here     
             populate(convertView);
        }

        return convertView;
}

//some code here to populate the view ...


}
4
Tobliug

J'ai un CursorAdapter qui ne peut pas être modifié avec un tableau de sauvegarde, car vérifier si l'élément doit être affiché ou non est obtenu après l'obtention du résultat de la base de données. J'ai implémenté la solution dans bindView(View v, Context context, Cursor c) selon une méthode similaire à celle décrite dans d'autres publications. Je pense que le meilleur moyen est de surcharger la méthode bindView() plutôt que getView(int position, View convertView, ViewGroup parent) car vous devriez effectuer environ null-ckecking pour convertView dans getView ().
La deuxième chose : J'ai essayé de cacher View v dans bindView(View v, Context context, Cursor c) et cela n'a pas fonctionné. Après enquête, j'ai compris que je devais masquer chaque élément en vue (y compris les mises en page contenant vos textes, images, etc.)

2
Subtle Fox

Un moyen simple de résoudre ce problème pour moi, il suffit d'analyser et de vérifier votre liste d'activité avant d'appeler la méthode "setAdapter" , par exemple

for(Object a : list){
//here must be some condition for getting all items without hidden
newList += a;
}
setAdapter(newList);
1
Igor Levkivskiy

Si vous créez votre propre adapter, vous pouvez le faire avec la méthode public View getView(int position, View convertView, ViewGroup parent). Cela peut être utile si vous envisagez d'afficher les éléments invisibles à un moment donné. Par exemple:

if(item.getYourRequirement == undesiredVlue)
    convertView.setVisibility(View.GONE);
else
    convertView.setVisibility(View.VISIBLE);

J'espère que ça aide

1
raukodraug

Un hack serait de définir la hauteur de l'élément de la liste que vous voulez masquer à 0. 

Mais, comme le dit seretur, la bonne approche consiste à retirer l’article et à utiliser notifyDataSetChanged(). Pourquoi cette solution n'est-elle pas appropriée dans votre cas?

1
Dave

Voici ma solution:

public class MyAdapter extends ArrayAdapter<MyEntry> {

    public MyAdapter(Context context, int resId) {
        super(context, resId);
    }

    private List<MyEntry> visibleEntries() {

        List<MyEntry> result = new ArrayList<MyEntry>();

        int i = 0;
        try {
            while (true) {
                if (getItem(i).isVisible())
                    result.add(getItem(i));
                i++;
            }

        } catch(Exception e) {

        }

        return result;

    }

    @Override
    public int getCount() {
        return visibleEntries().size();
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        LinearLayout layout = 
            convertView == null ? 
                (LinearLayout) LayoutInflater.from(getContext()).inflate(R.layout.entry, parent, false) :
                (LinearLayout) convertView;

        MyEntry entry = visibleEntries().get(position);

        ...

        return layout;
    }
}
0
almisoft

listview_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:orientation="horizontal"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:padding="10dp" >

<ImageView
    Android:id="@+id/imgView"
    Android:layout_width="40dp"
    Android:layout_height="20dp"/>

<TextView
    Android:id="@+id/totalTime"
    Android:layout_width="wrap_content"
    Android:layout_height="match_parent"
    Android:textSize="14dp"
    Android:text="16 分鐘"
    Android:layout_weight="1"
    Android:paddingLeft="10dp" />
<TextView
    Android:id="@+id/currentTime"
    Android:layout_width="wrap_content"
    Android:layout_height="match_parent"
    Android:textSize="14dp"
    Android:text="11:46"
    Android:layout_weight="1"
    Android:gravity="right"
    Android:paddingLeft="10dp" />
<ImageView
    Android:id="@+id/img"
    Android:layout_width="40dp"
    Android:layout_height="20dp"
    />
</LinearLayout>

MainActivity.Java

lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            view.findViewById(R.id.img).setVisibility(View.GONE);

        }
    });

c'est efficace pour moi.

0
deh3215