0

I want my ListView to hold View as each item, thus I wrote my own ArrayAdapter. That's to say, my ListView is a list of View now rather than TextView.

But now, how can I manage the items in the ListView? For example, if I want to change the background color of the view, it doesn't work if I put setBackgroundColor(Color.BLACK) inside the constructor of the View.

This is my custom ArrayAdapter code:

public class DataViewAdapter extends ArrayAdapter<DataView>{
Context context;
int layoutResourceId;
ArrayList<DataView> views;


public DataViewAdapter(Context context, int layoutResourceId,
        ArrayList<DataView> views) {
    super(context, layoutResourceId, views);
    this.context = context;
    this.layoutResourceId = layoutResourceId;
    this.views = views;
}

@Override
public View getView(int position, View convertView, ViewGroup parent){
    View row = convertView;
    ViewHolder holder = null;
    if(row == null){
        LayoutInflater inflater = ((Activity)context).getLayoutInflater();
        row = inflater.inflate(layoutResourceId, parent, false);
        holder = new ViewHolder();
        holder.view = (View)row.findViewById(R.id.dataView);
        row.setTag(holder);
    } else {
        holder = (ViewHolder)row.getTag();
    }
    DataView dataView = views.get(position);
    holder.view = dataView;
    return row;
}

static class ViewHolder{
    public View view;
}

}

Also, what if I need to pass different data values into each View? On accepting the new data values, the onDraw(Canvas canvas) method inside my DataView needs to be triggered.

EDIT: codes for DataView

public class DataView extends View{
    private LinkedList<Integer> data;
    public DataView(Context context){
        super(context);
        data = new LinkedList<Integer>();
    }
    public void onDraw(Canvas canvas){
    // I need to plot according to data
    }
    public void pushData(int value){
        data.add(value);
        this.invalidate();
    }
}
Cacheing
  • 3,431
  • 20
  • 46
  • 65

2 Answers2

0

You need to understand how ListView works. It doesn't simply have array of Views - these views are reused as user scrolls up/down to reserve the memory. What you need to do is to put your logic into Adapter#getView method and reset your backgrounds, fonts etc. there.

Of course you will need to extend the Adapter to add your code. It also very advaisable to use Holder pattern to save the references to the elements of your view so you don't have to search for these again and again. Here's example on how you may do it

EDIT: So based on your code snippet - you are not using Holder pattern correctly. Say your List item view is LinearLayout, then in your Holder constructor you do something like

this.title = (TextView)view.findViewById(R.id.title);

Then in Adapter#getView you can do things like

View getView(int position, View view, ViewGroup parent) {
    ViewHolder holder = null;
    if(row == null){
        LayoutInflater inflater = ((Activity)context).getLayoutInflater();
        view = inflater.inflate(layoutResourceId, parent, false);
        holder = new ViewHolder(view);
        view.setTag(holder);
    } else {
        holder = (ViewHolder)view.getTag();
    }
    // MyData is one piece of data in the backing array
    MyData data = (MyData)getItem(position); 
    if (data.important) {
        view.setBackground(Color.red);
        holder.title.setText(data.title);
    }
    return view;
}
Bostone
  • 36,858
  • 39
  • 167
  • 227
  • Thank you for your answer. Does it mean that if I want my View item to draw something using `Canvas`, it should be implemented by the `Holder`? – Cacheing Nov 13 '12 at 21:45
  • No. You use Holder to keep references such as say "TextView title" then in your getView method you refer to that as "holder.title". No need to mess with Canvas – Bostone Nov 14 '12 at 02:02
  • Sorry but I think I didn't make my problem clear. My `DataView` needs to plot some lines according to the values passed into it. And each time the `DataView` gets a new data, it needs to re-plot the lines. That's the reason why I need to use `Canvas`. Now, I don't know 1) how to pass the values (got from the main activity) to each item 2) where should I call the `invalidate()` method so that the `onDraw()` method within each `DataView` can be called. – Cacheing Nov 14 '12 at 03:29
  • Why are you sticking DataView into Holder? Simply do whatever you need to do with it and return it from the getView method – Bostone Nov 14 '12 at 15:31
  • I want the DataView to call onDraw method when there is data coming in. But now, the onDraw method is never called. – Cacheing Nov 15 '12 at 05:14
0

Normally you create/style your view in the getView() method of the adapter (perhaps you should extend BaseAdapter class instead of ArrayAdapter. But behold! The handling of the item views background is quite a special chapter. See the following question/answer for more on that:

Community
  • 1
  • 1
Ridcully
  • 23,362
  • 7
  • 71
  • 86
  • Thank you so much! Why do you say that it's better to extend `BaseAdapter` than `ArrayAdapter`? – Cacheing Nov 13 '12 at 20:23
  • Oh, forget it. I thought you couldn't override getView() in ArrayAdapter but that is not true. So it's perfectly fine to go with the ArrayAdapter. – Ridcully Nov 14 '12 at 12:51