Set onClickListener to getview () with ViewHolder class

I have a custom list adapter that extends BaseAdapter. I am creating a holder class to tag my views to avoid bloating the views that already exist.

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

      

and in my getView I have something 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 gets error from "holder.btnAdd.startAnimation (scale);" and says that the holder must be final ......

How can I fix this?

+2


source to share


2 answers


You should get view

using the method onClick

like this:

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

      

You are passing a parameter View v

to your method onClick

. Then your method is bound to the view, which is in your case:, holder.btnAdd

sov == holder.btnAdd



Update
It's a bit silly what I did to fix this problem. It's really easy, really, you initialize viewHolder

like null

, but you shouldn't. This is why you cannot make yours viewHolder

like 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;
}

      

What is it!

+6


source


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

Instead, use only 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();
         } }

      

0


source







All Articles