Question

I have a custom list adapter that extends BaseAdapter. I create a holder class to tag my views in order to avoid inflating views that already exist.

static class ViewHolder{
    TextView tvName;
    TextView tvDescription;
    Button   btAdd;
}

and in my getView i have somthing like this:

public View getView(int position, View convertView, ViewGroup parent) {
    View vi = convertView;
    ViewHolder holder = null;

    if(vi == null){
        vi = inflater.inflate(R.layout.list_row, null);
        holder = new ViewHolder();
        holder.tvName = (TextView)vi.findViewvById(R.id.name);
        holder.tvDescription = (TextView)vi.findViewvById(R.id.desc);
        holder.btAdd = (Button)vi.findViewvById(R.id.btnadd);
    }else{
        holder = (ViewHolder) vi.getTag();
    }

    holder.btnAdd.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            holder.btnAdd.startAnimation(scale);
        holder.tvName.setVisibility(View.GONE);
        }
    });
    return vi;
}

But eclipse get error from "holder.btnAdd.startAnimation(scale);" and says holder should be final......

How can I fix it?

Was it helpful?

Solution

You should get the view with the onClick method as follows:

holder.btnAdd.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        v.startAnimation(scale);
    }
});  

You pass the View v parameter in your onClick method. Then, your method is attached to the View which is in your case: holder.btnAdd, therefore v == holder.btnAdd

Update
It's a bit stupid what I did to resolve this. This is really easy, indeed you initialize viewHolder as null but you shouldn't. That's why you can't make your viewHolder as final:

public View getView(int position, View convertView, ViewGroup parent) {
    View vi = convertView;
    final ViewHolder holder; // without initialized

    if(vi == null){
        vi = inflater.inflate(R.layout.list_row, null);
        holder = new ViewHolder();
        holder.tvName = (TextView)vi.findViewvById(R.id.name);
        holder.tvDescription = (TextView)vi.findViewvById(R.id.desc);
        holder.btAdd = (Button)vi.findViewvById(R.id.btnadd);
    }else{
        holder = (ViewHolder) vi.getTag();
    }
    holder.btnAdd.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            v.startAnimation(scale);
            holder.tvName.setVisibility(View.GONE);
        }
    });
    return vi;
}

That's it!

OTHER TIPS

Based on this article https://scottweber.com/2013/04/30/adding-click-listeners-to-views-in-adapters/ You shouldn't make listener every time you call getView

Instead use just once

    @Override public View getView(int position, View convertView, ViewGroup parent) 
    {
    ViewHolder holder;
         if (convertView == null) {
             convertView = 
     LayoutInflater.from(getContext()).inflate(R.layout.row_simple, parent,
     false);
             holder = new ViewHolder();
             holder.text = (TextView) convertView.findViewById(R.id.text);
             holder.button = (Button) convertView.findViewById(R.id.button);
             holder.button.setOnClickListener(mMyButtonClickListener);
             convertView.setTag(holder);
         }
         else {
             holder = (ViewHolder) convertView.getTag();
         }

         holder.button.setTag(position);

         return convertView; }   

private View.OnClickListener mMyButtonClickListener = new View.OnClickListener() {
    @Override
         public void onClick(View v) {
             int position = (Integer) v.getTag();
             Toast.makeText(getContext(), "Row " + position + " was clicked!", Toast.LENGTH_SHORT).show();
         } }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top