Android ListView自定义布局

时间:2012-05-12 20:29:43

标签: android listview

我的Activity中有一个ListView,每行使用我的自定义布局和TextView以及两个按钮。当我单击这两个按钮中的任何一个时,我想要执行某个操作。在我的ArrayAdapter中,在getView方法中,我将onClickListeners设置为这两个按钮。

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

    View v = convertView;
    if (v == null) {
        v = li.inflate(R.layout.process_row, null);
    }


    final Button processCheck = (Button) v.findViewById(R.id.processCheck);
    processCheck.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            if (process.isChecked() == false) {
                process.setChecked(true);
                processCheck.setBackgroundColor(Color.BLUE);
            }
            else {
                process.setChecked(false);
                processCheck.setBackgroundColor(Color.RED);
            }

        }
    });

    return v;
}

ArrayList保存mz自定义类进程的对象,代码中的进程是此类的一个实例。所以现在当我在其中一个ListView行中单击此按钮时,我希望更改给定Process实例中的boolean变量并更改按钮的颜色。这种情况发生了,但不仅仅是这一行,还有3-4行。所以点击后,我有5个更改按钮而不是一个。你知道我在这里做错了什么吗?请注意,我不太了解ListActivity编码,大多数代码实际上是从示例文件中复制和编辑的。谢谢!

编辑:

问题可能只出在某个地方。当我单击按钮时,更多的颜色会改变颜色,但只有我点击的进程才会更改其布尔值。

4 个答案:

答案 0 :(得分:0)

问题在这里

View v = convertView;
    if (v == null) {
        v = li.inflate(R.layout.process_row, null);
    }

这是因为View v仅为可见项创建,然后重复使用。所以只需删除ifv == null)所以你的代码将是

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

    View v = convertView;

        v = li.inflate(R.layout.process_row, null);



    final Button processCheck = (Button) v.findViewById(R.id.processCheck);
    processCheck.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            if (process.isChecked() == false) {
                process.setChecked(true);
                processCheck.setBackgroundColor(Color.BLUE);
            }
            else {
                process.setChecked(false);
                processCheck.setBackgroundColor(Color.RED);
            }

        }
    });

    return v;
}

答案 1 :(得分:0)

每次呈现列表时都会调用getView。所以你应该添加你的gerview条件来设置颜色:public View getView(int position,View convertView,ViewGroup parent){

View v = convertView;

    v = li.inflate(R.layout.process_row, null);

//在下面添加这些行

if(process.isChecked()== false){

        processCheck.setBackgroundColor(Color.BLUE);
    }
    else {

        processCheck.setBackgroundColor(Color.RED);
    }

final Button processCheck = (Button) v.findViewById(R.id.processCheck);
processCheck.setOnClickListener(new View.OnClickListener() {

    @Override
    public void onClick(View v) {
        if (process.isChecked() == false) {
            process.setChecked(true);
            processCheck.setBackgroundColor(Color.BLUE);
        }
        else {
            process.setChecked(false);
            processCheck.setBackgroundColor(Color.RED);
        }

    }
});

return v;

}

答案 2 :(得分:0)

编辑:在帖子末尾找到“开箱即用”的示例!

因为您看到多行受到影响,我想它有一些事情要做,系统如何回收资源,可能对Button的引用不明确。

我不确定我在哪里学习这个练习(Android教程或我们以前通过这些教程学习android的开发人员)。但建议使用嵌套类ViewHolder

private static class ViewHolder {

    public Button processCheck;
}

将它放在适配器或您声明getView()的任何类中,并将其修改为:

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

    View v = convertView;
    $ViewHolder viewHolder; //wait for the magic!
    if (v == null) {
        v = li.inflate(R.layout.process_row, null);
        $viewHolder = new ViewHolder();
        $viewHolder.processCheck = (Button) v.findViewById(R.id.processCheck);
        $v.setTag(viewHolder);
        //ok we somewhat stuffed an object with the Button into our View... so what?
    }

    $viewHolder = (ViewHolder) v.getTag();
    //see explanation below

    $viewHolder.processCheck.setOnClickListener(new View.OnClickListener() {
    //set the onClickListener for this and only this button.
        @Override
        public void onClick(View v) {
            if (process.isChecked() == false) {
                process.setChecked(true);
                processCheck.setBackgroundColor(Color.BLUE);
            }
            else {
                process.setChecked(false);
                processCheck.setBackgroundColor(Color.RED);
            }

        }
    });

    return v;
}

(我用$标记了更改。我认为如果我使用eclipse,他们应该很容易发现。否则查找+替换^^)

因此getTag()将返回与被调用视图关联的Object。对象是如此令人难以置信的通用,您可以将其称为您创建的ViewHolder对象。因此,您可以引用该按钮并将其存储在对象中 现在,无论何时获得ListView,您都可以检索对象并设置OnclickListener新鲜和新的。这样你就只能调用一个监听器。

请注意,您无需再次致电v.setTag();以“保存”您的更改。

如果你做了一些疯狂的事情,比如在同一个列表中为不同的布局加注出于什么原因。您可能想要为它们分配不同的ViewHandlers,如:

if (v == null) {
    if( someCriteria) {
        v = li.inflate(R.layout.process_row, null);
        viewHolder = new ViewHolder(); 
    }
        v = li.inflate(R.layout.process_another_row, null);
        viewHolder = new AnotherViewHolder(); 
}

然后,对一个ViewHolder或其他ViewHolder进行未经检查的getView()调用可能会在运行时抛出错误!

答案 3 :(得分:0)

这就是我解决它的方法:

在我的适配器中,我创建了类:

private static class ViewHolder {
    public Button       processCheck;
    public Process      process;
    public TextView     name;
}

比我为我的按钮创建了一个自定义监听器:

private class CustomListener implements View.OnClickListener {

    public ViewHolder   viewHolder;

    public CustomListener(ViewHolder holder) {
        this.viewHolder = holder;
    }

    @Override
    public void onClick( View v ) {
        if (viewHolder.process.isChecked()) {
            viewHolder.name.setText("not checked");
            viewHolder.process.setChecked(false);               
        }
        else {
            viewHolder.name.setText("checked");
            viewHolder.process.setChecked(true);                
        }           
    }
}

我的getView功能:

public View getView( int position, View convertView, ViewGroup parent ) {
    ViewHolder viewHolder;

    if ( convertView == null ) {
        convertView = mInflater.inflate( R.layout.process_row, null );

        viewHolder = new ViewHolder();
        viewHolder.processCheck = (Button) convertView.findViewById(R.id.processCheck);
        viewHolder.name = (TextView) convertView.findViewById(R.id.processName);            
        convertView.setTag( viewHolder );
    }


    viewHolder = (ViewHolder) convertView.getTag();
    viewHolder.process = list.get(position);

    if (viewHolder.process.isChecked()) {
        viewHolder.name.setText("checked");         
    } 
    else {
        viewHolder.name.setText("not checked");         
    }       

    CustomListener listener = new CustomListener( viewHolder );
    viewHolder.processCheck.setOnClickListener(listener);

    return convertView;
}