как скрыть элемент в виде списка в android

<p>я знаю, этот вопрос задавался раньше, но я не видел рабочего ответа на него.</p><p>есть ли способ скрыть некоторые элементы в <code>listview</code> без изменения исходных данных?</p><p>я попытался сделать так, чтобы видимость элемента исчезла, он больше не будет отображаться, но место, зарезервированное для этого элемента, все еще там.</p><p>я также установил:</p><pre><code>android:dividerheight="0dp" android:divider="#ffffff" </code></pre><p>безуспешно.</p>

<p>вы можете написать свой собственный <code>listadapter</code> или подкласс одного из существующих.</p><p>в вашей <code>listadapter</code> вы просто отфильтровываете элементы, которые вы не хотите отображать, возвращая измененные значения для <code>getcount()</code>, <code>getitem()</code> и <code>getitemid()</code> в зависимости от ситуации.</p>

<p>я пробовал несколько решений, в том числе <code>setvisibitlity(view.gone)</code> и раздувание представления <code>null</code> по умолчанию, но у всех них есть общая проблема, и это то, что разделители между скрытыми элементами складываются и создают плохо видимое серое пространство в больших списках.</p><p>если ваш <code>listview</code> поддерживается <code>cursoradapter</code>, то лучшим решением будет обернуть его <code>cursorwrapper</code>.</p><p>поэтому мое решение (основанное на ответе @romanusachev <a href="https://stackoverflow.com/a/17333945/191148">здесь</a> ) заключается в следующем:</p><p><strong>filtercursorwrapper</strong></p><pre><code> 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; } } </code></pre><p>когда ваш <code>cursor</code> готов, отправьте <code>filtercursorwrapper</code> с нужным индексом столбца</p><pre><code>filtercursorwrapper filtercursorwrapper = new filtercursorwrapper(cursor, true,data\_column\_index); dataadapter.changecursor(filtercursorwrapper); </code></pre><p>и если вы делаете фильтрацию и сортировку, не забудьте использовать <code>filtercursorwrapper</code> везде:</p><pre><code> 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); } }); </code></pre><p>и для обновления списка достаточно запроса с пустым фильтром:</p><pre><code>dataadapter.getfilter().filter(""); </code></pre><p>и все готово, просто изменив логику метода <code>ishidden</code>, вы можете показать или скрыть скрытые элементы. и выгода в том, что вы не видите сложенных нежелательных разделителей. :-)</p>

<p>если вы хотите скрыть элемент следующим образом:</p><pre><code>convertview.setlayoutparams(new abslistview.layoutparams(-1,1)); convertview.setvisibility(view.gone); </code></pre><p>не может быть abslistview.layoutparams (-1,0);</p><p>если convertview повторно используется, вы должны добавить это ниже, чтобы установить его высоту:</p><pre><code>if(convertview.getvisibility() == view.gone) { convertview.setvisibility(view.visible); convertview.setlayoutparams(new abslistview.layoutparams(-1,-2)); } </code></pre>

<p>в некоторых случаях у вас есть простое решение:</p><p>я должен скрыть представление в виде списка, потому что элементы, которые заполняют представление, недопустимы, поэтому я не хочу видеть представление:</p><p>в моем списке адаптер:</p><pre><code>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 ... } </code></pre>

<p>у меня есть <code>cursoradapter</code>, который нельзя изменить с помощью резервного массива, потому что проверка того, должен ли элемент отображаться или нет, была после получения результата из базы данных. я реализовал решение в <code>bindview(view v, context context, cursor c)</code> аналогичным способом, как было описано в других постах. <strong>я думаю</strong>, что лучшим способом является переопределение метода <code>bindview()</code>, а не <code>getview(int position, view convertview, viewgroup parent)</code>, потому что вы должны иметь дело с null-ckecking для convertview в getview ().<br> <strong>вторая вещь</strong>: я пытался скрыть <code>view v</code> в <code>bindview(view v, context context, cursor c)</code>, и это не сработало. после расследования я понял, что мне нужно скрыть <strong>каждый элемент в поле зрения</strong> (включая макеты, содержащие ваши тексты, изображения и т.д.)</p>

<p>простой способ решить эту проблему для меня<strong> просто проанализируйте и проверьте свой список в действии перед вызовом метода "setadapter" </strong>, например:</p><pre><code>for(object a : list){ //here must be some condition for getting all items without hidden newlist += a; } setadapter(newlist); </code></pre>

<p>если вы создаете свой собственный <code>adapter</code>, вы можете сделать это с помощью метода <code>public view getview(int position, view convertview, viewgroup parent)</code>. это может быть полезно, если вы планируете показать невидимые элементы в какой-то момент. например:</p><pre><code>if(item.getyourrequirement == undesiredvlue) convertview.setvisibility(view.gone); else convertview.setvisibility(view.visible); </code></pre><p>надеюсь, это поможет</p>

<p>хаком было бы установить высоту элемента списка, который вы хотите скрыть, равным 0. </p><p>но, как говорит seretur, правильный подход - удалить элемент и использовать <code>notifydatasetchanged()</code>. почему это решение не подходит в вашем случае?</p>

<p>вот мое решение:</p><pre><code>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; } } </code></pre>

<p>listview\_item.xml</p><pre><code><?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> </code></pre><p>mainactivity.java</p><pre><code>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); } }); </code></pre><p>это эффективно для меня.</p>