How can you hide an item in a ListView or at least set its height to zero?
I have tried setting the visibility of the View to GONE but it still maintains the item's space (height).
How can you hide an item in a ListView or at least set its height to zero?
I have tried setting the visibility of the View to GONE but it still maintains the item's space (height).
Ressurecting an old question, but I just had this issue where I wanted to hide list items temporarily based upon criteria outside of the list data. What I ended up doing was creating a "null item" layout in xml and returned that based upon my criteria instead of the convert view in getView()...
instead of returning the convertView, I returned my null_item...
return inflater.inflate(R.layout.null_item, null);
null_item.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</LinearLayout>
if you want to hide the item like this:
convertView.setLayoutParams(new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,1));
convertView.setVisibility(View.GONE);
can't be AbsListView.LayoutParams(-1,0);
if convertview are reused you should add this below to set it height back:
if(convertView.getVisibility() == View.GONE) {
convertView.setLayoutParams(new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, AbsListView.LayoutParams.WRAP_CONTENT));
convertView.setVisibility(View.VISIBLE);
}
When it comes to ListView, to make it efficient, we use ViewHolder pattern. The way to use ViewHolder Pattern and R.layout.row_null of the following xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</LinearLayout>
is to use with getViewTypeCount() and getItemViewType(int position) as follow.
@Override
public int getViewTypeCount() {
return 2;
}
@Override
public int getItemViewType(int position) {
return (hideStatusCheck(position)) ? 1 : 0;
}
@Override
public View getView(int pos, View convertView, ViewGroup parent) {
View rowView = convertView;
if (hideStatusCheck(pos)) {
if (rowView == null || rowView.getTag() != null) {
LayoutInflater inflater = mActivity.getLayoutInflater();
rowView = inflater.inflate(R.layout.row_null, parent, false);
}
} else {
if (rowView == null) {
rowView = inflateNormalView(parent);
} else if (rowView.getTag() == null) {
rowView = inflateNormalView(parent);
} else {
ViewHolder holderToCheck = (ViewHolder) rowView.getTag();
Integer storedPos = (Integer) holderToCheck.getTag(POSITION);
if (storedPos == null || storedPos != pos)
rowView = inflateNormalView(parent);
}
ViewHolder holder = (ViewHolder) rowView.getTag();
holder.setTag(POSITION,pos);
/*
Populate data
*/
return rowView;
}
private View inflateNormalView(ViewGroup parent) {
View rowView;
LayoutInflater inflater = mActivity.getLayoutInflater();
rowView = inflater.inflate(R.layout.normal_item, parent, false);
ViewHolder viewHolder = new ViewHolder();
assert rowView != null;
/* Initiate normal findViewById thing*/
rowView.setTag(viewHolder);
return rowView;
}
We do the checking of the item's View type and if it meets the hide check, it will return 1, otherwise 0. The ListView knows that there will be 2 types of View from getViewTypeCount. Now, the getView will return the approriate View depending on the hideStatusCheck. To make a robust ListView, we want to use the ViewHolder pattern. We don't need to use ViewHolder when it is hidden. We simply inflate the R.layout.row_null and return it. We will use the ViewHolder for the R.layout.normal_item. Here is the tricky part assuming the hiding check is not static. The first check of rowView==null
is standard. The second check of rowView.getTag()==null
is to see if the View is coming back to normal
from hiding. The third check in the last else
clause is to check if the ViewHolder retained in the tag is the right ViewHolder. If these conditions are met, we always inflate the view again. Yes, it is true that, the ViewHolder pattern is not used throughout but it uses to certain extends. It is better than nothing.
I did some tinkering with a drag and drop list from here. When an item is popped out of the list to be moved around the cell space it occupied has it's height set to 1px (see line 238) so it appears "gone". I couldn't find a way to handle this better as setting height to 0 fails as does visibility GONE.
That said, If you really want to get rid of a row less temporarily, it might be a good idea to change the backing of the Adapter
and call notifyDataSetChanged()
on it.
I have look at source code. And there is only one way to hide item without notifyDataSetChanged()
. You must set visibility GONE
for all inner views and remove background image and paddings for item's view.
Note: Row with such invisible element will be selectable.
P.S: This is very usefull for ExpandableListView
if you want to hide group view it self.
add to your ListView object: android:dividerHeight="0px" android:divider="#FFFFFF"
Divider color doesn't matter only setting dividerHeight doesn't work
This does remove the divider though...
I think I have a much easier / safer solution: you just have to "embed" your item in a Layout, and change the visibility of this parent layout.
<?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="wrap_content"
android:orientation="horizontal" >
<!-- Embed ListView Item into a "parent" Layout -->
<LinearLayout
android:id="@+id/parentLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<!-- This is the normal content of your ListView Item -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="World" />
</LinearLayout>
</LinearLayout>
Then in your code just do:
public View getView(int position, View view, ViewGroup parent) {
if (view == null) {
LayoutInflater li = mActivity.getLayoutInflater();
view = li.inflate(R.layout.my_listview_item, null);
}
LinearLayout parentLayout = (LinearLayout) view.findViewById(R.id.parentLayout);
if (shouldDisplayItem(position)) {
parentLayout.setVisibility(View.VISIBLE);
} else {
parentLayout.setVisibility(View.GONE);
}
return view;
}
This way you always use/reuse the same item, and just hide/show it.