when my ListView is being filled by a custom Array Adapter, I check for a certain parameter in the current list item, and if it is false, I want to return an empty row. At the moment, I am doing this by inflating an empty xml file, but that creates ugly list item dividers when a number of items should not be shown, and is obviously not the best way ;-)!
if (list.get(position).equals("i-dont-want-this-in-the-list-view")){
View empty=inflater.inflate(R.layout.empty_row, parent, false);
return(empty);
}
I have tried to return "null", but it clearly expects a View to be returned. Is there anything I could do without having to filter the list that is being used for the ListView beforehand (I want to keep it intact as I am doing other things with it, too).
Thanks,
Nick
To fix the issue of line dividers, remove the line dividers from the ListView and put your own in inside the individual items.
Inflate a View and setVisibility to VIEW.GONE
What's about:
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
//use a global Array to set the rows visible/hidden and return empty rows
if(disArray[position] == false) return new View(getContext());
... // continue with your getView() implementation
return convertView;
}
to update the ListView use
adapter.notifyDataSetChanged();
What're in the rows that aren't empty? Images can be replaced by empty, transparent pngs and text views can be set to "", etc.
View.Gone will give u empty list row. try using layout params and set to zero value like this:
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(0,0);
viewholder.programRow.setLayoutParams(layoutParams);
Layoutparams should be used as according to parent viewgroup used
Related
I'm trying to implement a custom listview. Everything works fine until I use a if () statement inside the getView() method
Without the if() condition a single item gets selected when I select an item but when I add the if() condition, the views are displayed properly but two items (non-adjacent) get selected (1st and last 1st or and second-last, any such combination).
View getView(...){
....
if (!item.getPriceTo().equals(""))
priceToTV.setText(item.getPriceTo());
else
priceToTV.setText(item.getPriceFrom());
return view;
}
Also I'm using saving the previous view to show the selection so the current selection has a red_border and when it is selected a black_border is set to it.:
subItemsListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Log.d("New Order", "........");
if (previousViewOfSubItems != null && previousViewOfSubItems != view) {
previousViewOfSubItems.setBackgroundResource(R.drawable.black_border);
if (quantity.getText().toString().equals("xx") || quantity.getText().toString().equals("0")) {
viewForVisibility.setVisibility(View.GONE);
layoutForQuantity.setVisibility(View.GONE);
}
}
if (previousViewOfSubItems == view)
return;
previousViewOfSubItems = view;
previousViewOfSubItems.setBackgroundResource(R.drawable.red_border);
viewForVisibility = previousViewOfSubItems.findViewById(R.id.viewForVisibility);
viewForVisibility.setVisibility(View.VISIBLE);
layoutForQuantity = (LinearLayout) previousViewOfSubItems.findViewById(R.id.layoutForQuantity);
layoutForQuantity.setVisibility(View.VISIBLE);
quantity = (TextView) previousViewOfSubItems.findViewById(R.id.subTypeQuantity);
}
});
previousViewOfSubItems = view; seems to be causing the problem,
In Listviews with adapter you should avoid saving view instances, because views are reused by adapters so view can be same for two rows so rather than saving view instance's reference use ViewHolder Design pattern and use view tagging
You need to use ViewHolder Pattern and view tagging to properly identify every view in different position. ListView always recycle the view instead of re-inflating the view again and again.
You can refer to Android Training documentation on how to implement ViewHolder pattern.
ListViews recycle the views in the list. so as you scroll, top views are reused and content replaced using the methods.
Where you set background to Red etc, use Else statements to set it back to your default black.
its beacause it listview reuses view to display items, once the first view is scrolled out the the same view is reused to display the view at bottom of the listview. instead of comparing the view try compairing the position of the view clicked
I have explained about this abnormal behavior in my blog on recyclerview you refer that to solve this problem.
use pojo class to get the status and update the view accordingly
I wanted to know how I may go about creating a loop for setting a specific background colour to each of my listview items in a reoccurring pattern. Say I have 10 items and 4 colours and I want the 10 items to be coloured in order of the pattern and for it to repeat, until the items are all coloured. Considering I have the following colours in an Integer Array:
int[] colours = {Color.RED, Color.BLUE, Color.GREEN, Color.MAGENTA};
Well, I would implement a custom Adapter or a ViewBinder for this.
In case of an Adapter, for example ArrayAdapter you have to override the getView method
...
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if (view == null) {
view = getActivity().getLayoutInflater().inflate(R.layout.item, null);
}
view.setBackgroundColor(colors[position % colors.length]);
return view;
}
....
First off, you have to be clear about two things:
This should go in the process of getView()
getView() renders your rows, but it doesn't sequentially. Performance depends very much on your layout implementation, but you cannot guarantee your rows will be rendered in order.
That said, I think there could be a way to do this:
Prior to passing your data to your ArrayAdapter, define an extra variable in your ArrayList, you should use a class if you're not yet using it.
Assign it the number of the background you want to set it. Ideally, this should be an int with the Color.YOURCOLOR you want to set it.
Once processing within your getView() method, get that data for the row and simply call:
YourClass item = (YourClass) getItem[position];
convertView.setBackgroundColor(item.getMyColor());
I would like to show/hide items in my listview. Currently I am doing this by iterating through adapter's data. If item at certain index matches some condition, this line is called:
listView.getChildAt(index).setVisibility(View.GONE);
Item is not visible, but blank space remains (surprisingly View.GONE and View.INVISIBLE acts the same in this case).
I would like to achieve the same effect as if item was deleted from adapter and notifyDataSetChanged() was called, but I don't want to modify underlying data, just hide the item.
I have achieved this as Tonithy suggests here. Added an if clause at the begining of getView method in adapter, which checks if item matches condition to hide. If it does getView returns "null layout".
When I want to hide an item, I set a condition and call .invalidateViews() on my listview.
Do not return different views based on internal property without letting listview know about it, you should reuse views! Otherwise you make very slow apps. For example, take look at this tutorial with benchmark.
getView(...) - reuse convertView!, hide it conditionaly!
use Holder classes, make them "listen" to your adapter signals/evens and change their visual conditionally
Alternative: You can use multiple types of list items within single list:
define list item types (shown, hidden), override getViewTypeCount(): return 2
override getItemViewType(...),
is shown -> 0
is not shown -> 1
more complex getView(...)
get item view type or check if it's shown
dispatch view creation based on type, don't forget, that convertView argument is view for current item type, you should reuse it, if not null!
on change call notifyDataSetChanged()
I have tested approached like this for different stable types, but it should work even when type for item changes and you let observer know about it. This approach will be a lot of faster than one you have posted, because, you reuse views, don't need to always inflate new one!
Call .setVisibility(View.GONE) in override getView method of your CustomeListAdapter for all UI elements of your custom_list_item.
For Example:
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
Holder holder = new Holder();
View rowView;
rowView = inflater.inflate(R.layout.custom_list_item, null);
holder.tvName = (TextView) rowView.findViewById(R.id.textViewName);
holder.img = (ImageView) rowView.findViewById(R.id.imageView1);
if (items[position].NeedForCollapsed){
System.out.println("set Visibility.Gone");
holder.tvName.setVisibility(View.GONE);
holder.img.setVisibility(View.GONE);
return rowView;
}
//new values
holder.tvName.setText(items[position].name);
holder.img.setImageResource(GetImageID(items[position]));
return rowView;
}
public class Holder
{
TextView tvName;
ImageView img;
}
Or call .setVisibility(View.GONE) for your root container like a LinearLayout.
good luck!
I have a strange problem. I am setting the background color of the items of a listview like so:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
...
if (status == true) {
row.setBackgroundColor(Color.argb(255,0,85,187));
}
else {
if (morestuff) {
row.setBackgroundColor(Color.argb(128,255,0,0));
}
}
...
}
This seems to work. However, when i scroll on the listview, and then back, some of the rows have acquired a color from another row without being set by this code. I suspect the listview is recycling the views as an optimization.
How can I fix this?
The getView will be called all the time when the listview is drawn. Simply taking it will be called when we do a small change example do a small scroll
If you want to set color to a specific row, Just do it by checking the position (First argument of getview).
The list view is definately recycling views as an optimization. You should look at the efficient list view example for ideas.
How to do my own custom list? I mean, that each element of list will be looking like I want.
Create a custom list item row layout
You have to create a custom list row item in the layout folder, just like you define the usual activity layouts. There you place your icons, TextViews etc and place them properly.
Override the specific adapter you need
You then need to override the specific adapter you need in order to associate the data from your curso / object list with your layout xml element. This is usually done by overriding the getViewor bindView method of the adapter of your choice (ResourceCursorAdapter, ArrayAdapter,..).
#Override
public View getView(int position, View convertView, ViewGroup parent){
if(convertView == null){
convertView = mInflater.inflate(R.layout.row_item, parent, false);
}
TextView someTextViewOnMyRowLayout = (TextView)findViewById(...);
someTextViewOnMyRowLayout.setText(...);
return convertView;
}
You can create an xml file which acts as an element that looks like you want..
and assign that to the list using inflators and adapters..
Try this..
http://www.softwarepassion.com/android-series-custom-listview-items-and-adapters/ ,
http://www.androidpeople.com/android-custom-listview-tutorial-example/