连续按钮的自定义arrayadapter和onclicklistener

Posted

技术标签:

【中文标题】连续按钮的自定义arrayadapter和onclicklistener【英文标题】:Custom arrayadapter and onclicklistener for a button in a row 【发布时间】:2014-02-05 08:53:19 【问题描述】:

我有一个自定义的arrayadapter,我想在它的每一行中为一个按钮添加一个 onclicklistener,当我单击按钮时,我希望更改图像资源,除了单击按钮时,一切正常图像会发生变化,但另一行中另一个按钮的图像也会发生变化。谢谢你的帮助 ! 这是我的代码:

    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;
    

【问题讨论】:

尝试将 holder.b.setTag(holder); 移动到 else 部分下方。您的问题是因为 lsitview 回收视图。 你得到解决方案了吗。谢谢 【参考方案1】:

检查代码完成了一些更改

包 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;
    

将您的点击监听器放在 if 条件中,并在 if else 条件之外设置标签

【讨论】:

很抱歉,我按照你告诉我的方式更新了我的 getview,但我仍然遇到完全相同的问题! 尝试调试你的点击事件并检查你得到了什么。这可能是不同的事情 调试时一切正常,单击按钮时只有一个单击事件,但不知何故另一个按钮也发生了变化 尝试通过更改 row = inflater.inflate(layoutResourceId, parent, false); to row = inflater.inflate(layoutResourceId, null);让我知道 对不起@dinesh sharma,我复制粘贴了你的代码,改变了膨胀表达式,还是同样的问题【参考方案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;

【讨论】:

那没用,我照你说的做了,但我仍然有同样的问题 只需将 getView 方法替换为我编辑的内容即可。试一次 我复制/粘贴了您的getview,但它不起作用,同样的问题,当我单击一个按钮时,另一行中的另一个按钮也发生了变化【参考方案3】:

您的问题和两个答案都有一个常见的误解。

首先,请确保您了解 ListView 的回收工作原理。比如this post就稍微解释一下这个问题。

关于这个具体案例,我们先来了解一下问题所在。当你点击一个按钮时,图像会改变,一切看起来都很好。但是,如果您滚动,您将在另一个位置获得相同的视图(带有更改图像的按钮)。因为回收。

要解决此问题,您必须维护按钮的图像选择。这不会神奇地发生。您必须添加一些逻辑来告诉此方法应在特定位置显示哪个图像资源。

例如,在您的 getView() 方法中,添加以下(伪)代码:

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】:

发生这种情况的原因是适配器在滚动时回收视图。

例如,假设您总共有 15 行,并且一次有 5 行适合屏幕。 if(row == null) 部分仅对前 5 行执行。当您向下滚动到第 6 行时,它使用第 1 行的视图。这就是为什么你应该在 if-else 子句之后设置 View 的内容。所以现在,当第 6 行进入屏幕时,行不是null。它拥有第一行的视图。当它执行holder.name.setText(name1); 时,它将第 1 行的名称替换为第 6 行的名称。同样,第 7 行使用第 2 行的视图,依此类推。

现在,假设您单击第一行的按钮。第一行的视图发生变化,w.b.setImageResource(R.drawable.butgreen); 设置第一行按钮的图像资源。当您滚动到第 6 行时,它使用第 1 行的视图。但是您仅将 holder.name 设置为第 6 行的名称。第一行按钮的图像资源将保留在那里,从而导致您的问题。

解决方案:创建另一个ArrayList&lt;String&gt; 并将按钮的状态存储在其中。因此,在您的情况下,我假设按钮的颜色为“红色”或“绿色”。您可以在每个位置存储“红色”或“绿色”,表示每个按钮当前的颜色(您可以将此 ArrayList 初始化为红色)。然后,当每行加载时,您可以设置图像资源以及该行的名称。看看下面的代码。我已将 cmets 添加到我添加的行中。

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;


【讨论】:

以上是关于连续按钮的自定义arrayadapter和onclicklistener的主要内容,如果未能解决你的问题,请参考以下文章

ListView 中自定义 ArrayAdapter 的自定义过滤

android中自定义ArrayAdapter中的自定义getFilter

使用android中的自定义arrayadapter在listview中使用复选框检查后如何删除多个项目?

ListView 中的自定义过滤 ArrayAdapter

按钮未显示在android的自定义列表视图中

搜索在 ArrayAdapter 和 ListView 中不起作用