Custom arrayadapter and onclicklistener for a button in a row

ε祈祈猫儿з 提交于 2019-12-11 07:41:03

问题


I have a custom arrayadapter and I want to add an onclicklistener for a button in each one of its rows, when I click on the button I want the image resource to change, everything works fine except that when I click on a button the image changes but the image of another button in an other row also changes. Thanks for your help ! Here is my code:

    public class Coursadapter extends ArrayAdapter<String>{

    Context context; 
    int layoutResourceId;    
    ArrayList<String> data = null;
    WeatherHolder holder;

    public Coursadapter(Context context, int layoutResourceId, ArrayList<String> data) {
       // super(context, layoutResourceId, data, coeff);
        super(context, layoutResourceId, data);
        this.layoutResourceId = layoutResourceId;
        this.context = context;
        this.data = data;

    }

    public View getView(int position, View convertView, ViewGroup parent) {
        View row = convertView;


        if(row == null)
        {
            LayoutInflater inflater = ((Activity)context).getLayoutInflater();
            row = inflater.inflate(layoutResourceId, parent, false);

            holder = new WeatherHolder();
            holder.name = (TextView)row.findViewById(R.id.item_cours_name);
            holder.b=(ImageButton) row.findViewById(R.id.button);
            holder.b.setTag(holder);
            row.setTag(holder);
        }
        else
        {
            holder = (WeatherHolder)row.getTag();
        }

        holder.b.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                WeatherHolder w = (WeatherHolder) v.getTag();
                w.b.setImageResource(R.drawable.butgreen);


            }
        });
        String name1 = data.get(position);
        holder.name.setText(name1);


        return row;
    }

    static class WeatherHolder
    {

        TextView name;
        ImageButton b;
    }
}

回答1:


Few changes done check out the code

package com.example.dontpanic;

public class Coursadapter extends ArrayAdapter<String> {

    Context context;
    int layoutResourceId;
    ArrayList<String> data = null;
    WeatherHolder holder;

    public Coursadapter(Context context, int layoutResourceId,
            ArrayList<String> data) {
        // super(context, layoutResourceId, data, coeff);
        super(context, layoutResourceId, data);
        this.layoutResourceId = layoutResourceId;
        this.context = context;
        this.data = data;

    }

    public View getView(int position, View convertView, ViewGroup parent) {
        View row = convertView;

        if (row == null) {
            LayoutInflater inflater = ((Activity) context).getLayoutInflater();
            row = inflater.inflate(layoutResourceId, parent, false);

            holder = new WeatherHolder();
            holder.name = (TextView) row.findViewById(R.id.item_cours_name);
            holder.b = (ImageButton) row.findViewById(R.id.button);
            holder.b.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    // TODO Auto-generated method stub
                    WeatherHolder w = (WeatherHolder) v.getTag();
                    w.b.setImageResource(R.drawable.butgreen);
                }
            });
            row.setTag(holder);

        } else {
            holder = (WeatherHolder) row.getTag();
        }

        holder.b.setTag(holder);
        String name1 = data.get(position);
        holder.name.setText(name1);

        return row;
    }

    static class WeatherHolder {

        TextView name;
        ImageButton b;
    }
}

put your click listener inside if condition and set tag outside of the if else condition




回答2:


public View getView(int position, View convertView, ViewGroup parent) {
    if(convertView == null)
    {
        LayoutInflater inflater = ((Activity)context).getLayoutInflater();
        convertView = inflater.inflate(layoutResourceId, parent, false);

    }
   TextView name = (TextView)convertView.findViewById(R.id.item_cours_name);
   ImageButton b=(ImageButton) convertView.findViewById(R.id.button);
   b.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
           b.setImageResource(R.drawable.butgreen);
        }
    });
    String name1 = data.get(position);
    name.setText(name1);
    return convertView;
}



回答3:


There's a common misunderstanding that your question and both answers share.

First of all, make sure you understand how ListView's recycling works. For example, this post explains this matter a bit.

Regarding this specific case, let's first understand the problem. When you click on a button, the image is changed and everything looks OK. But if you scroll, you will get the same view (with button that has a changed image) in another position. Because of recycling.

To fix this problem, you have to maintain your button's image selection. This won't magically happen. You have to add some logic that tells this method which image resource should be displayed in a particular position.

For example, in your getView() method, add the following (pseudo)code:

public View getView(int position, View convertView, ViewGroup parent) {
    View row = convertView;
    if(row == null) {
        // omitted..
    }
    else {
        holder = (WeatherHolder)row.getTag();

        // BUTTON's IMAGE MAINTAINING
        if(condition) {
           w.b.setImageResource(R.drawable.butgreen);
        } else {
           w.b.setImageResource(some-other-image-resource);
        }
    }

    // omitted..

    return row;
}



回答4:


The reason why this happens is because the adapter recycles the views on scrolling.

For example, suppose you have a total of 15 rows and 5 rows fit on the screen at a time. The if(row == null) part executes for the first 5 rows only. When you scroll down to the 6th row, it uses the View of the 1st row. This is why you are supposed to set the content of your View after the if-else clause. So now, when the 6th row comes into the screen, row is not null. It holds the View of the 1st row. When it executes holder.name.setText(name1);, it is replacing the name of the 1st row with the name of the 6th row. Similarly, the 7th row uses the view of the 2nd row and so on.

Now, suppose you click on the button in the 1st row. The View for the 1st row changes and w.b.setImageResource(R.drawable.butgreen); sets the image resource of the button in the 1st row. When you scroll to the 6th row, it uses the View of the 1st row. But you are setting only holder.name to the name of the 6th row. The image resource of the button in the 1st row is going to remain there, hence causing your problem.

Solution: Create another ArrayList<String> and store the status of the button in this. So in your case, I'm assuming the buttons are either "red" or "green" in color. You could store either "red" or "green" at each position signifying what color each button is currently (you can initialize this ArrayList to red). Then, when each row loads, you can set the image resource along with the name of that row. Take a look at the code below. I have put comments to the lines I added.

public class Coursadapter extends ArrayAdapter<String> {

Context context;
int layoutResourceId;
ArrayList<String> data = null;
WeatherHolder holder;
ArrayList<String> colors; // Stores the color of each button

public Coursadapter(Context context, int layoutResourceId, ArrayList<String> data) {
    // super(context, layoutResourceId, data, coeff);
    super(context, layoutResourceId, data);
    this.layoutResourceId = layoutResourceId;
    this.context = context;
    this.data = data;
    this.colors = new ArrayList<>(Collections.nCopies(data.size(), "red")); // initialize all the buttons to red color
}

public View getView(final int position, View convertView, ViewGroup parent) {
    View row = convertView;


    if(row == null)
    {
        LayoutInflater inflater = ((Activity)context).getLayoutInflater();
        row = inflater.inflate(layoutResourceId, parent, false);

        holder = new WeatherHolder();
        holder.name = (TextView)row.findViewById(R.id.item_cours_name);
        holder.b=(ImageButton) row.findViewById(R.id.button);
        holder.b.setTag(holder);
        row.setTag(holder);
    }
    else
    {
        holder = (WeatherHolder)row.getTag();
    }

    if(colors.get(position).equals("red")) {
        holder.b.setImageResource(R.drawable.butred); // set the colors of the button to red or whatever you need
    } else {
        holder.b.setImageResource(R.drawable.butgreen); // set the colors of the button to green
    }

    holder.b.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            WeatherHolder w = (WeatherHolder) v.getTag();
            //w.b.setImageResource(R.drawable.butgreen);
            colors.set(position, "green"); // update the ArrayList colors
        }
    });
    String name1 = data.get(position);
    holder.name.setText(name1);


    return row;
}

static class WeatherHolder
{

    TextView name;
    ImageButton b;
}
}


来源:https://stackoverflow.com/questions/21161959/custom-arrayadapter-and-onclicklistener-for-a-button-in-a-row

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!