【问题标题】:Android: Checkbox in listview (how to create OnCheckedChangeListener in Adapter)Android:列表视图中的复选框(如何在适配器中创建 OnCheckedChangeListener)
【发布时间】:2018-01-28 13:52:18
【问题描述】:

我正在创建一个待办事项列表应用程序,我有一个关于在列表适配器中使用复选框及其侦听器的问题。我在列表视图中的单行包含三个 TextView 和一个复选框。当用户“选中”复选框时,我想更改单行的背景。我已经读过我应该将复选框侦听器放在我的适配器类中,所以我做到了。现在是问题所在 - 当我在列表视图中添加几行并且未选中所有复选框时,所有这些都可以正常工作,但是当我添加一行时,选中复选框并尝试添加另一个我得到错误

java.lang.NullPointerException:尝试在空对象引用上调用虚拟方法“void android.view.View.setBackgroundColor(int)”

下面是我的适配器的代码。谢谢你的任何建议。我刚开始使用 Android 编程,所以提前感谢您的理解。

public class ToDoAdapter extends ArrayAdapter<ToDoTask> {


ArrayList<ToDoTask> objects;
Context context;
int resource;

public ToDoAdapter(@NonNull Context context, @LayoutRes int resource, @NonNull ArrayList<ToDoTask> objects) {
    super(context, resource, objects);
    this.objects = objects;
    this.context = context;
    this.resource = resource;
}

@Override
public View getView(final int position, View convertView, final ViewGroup parent) {
    View view = convertView;
    ToDoHolder toDoHolder = null;

    if (view == null) {
        LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        view = layoutInflater.inflate(R.layout.row, parent, false);

        toDoHolder = new ToDoHolder();
        toDoHolder.rowTitle = (TextView) view.findViewById(R.id.rowTitle);
        toDoHolder.rowDesc = (TextView) view.findViewById(R.id.rowDesc);
        toDoHolder.rowDate = (TextView) view.findViewById(R.id.rowDate);
        toDoHolder.rowIsDone = (CheckBox) view.findViewById(R.id.rowCheckBoxDone);

        toDoHolder.rowIsDone.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
                if(checked){
                    parent.getChildAt(position).setBackgroundColor(Color.parseColor("#8FE370"));
                }
                else
                    parent.getChildAt(position).setBackgroundColor(Color.WHITE);
            }
        });

        view.setTag(toDoHolder);
    } else {
        toDoHolder = (ToDoHolder) view.getTag();
    }

    ToDoTask object = objects.get(position);
    toDoHolder.rowTitle.setText(object.getTitle());
    toDoHolder.rowDesc.setText(object.getDescription());
    toDoHolder.rowDate.setText(object.getDate());
    toDoHolder.rowIsDone.setChecked(object.getDone());

    return view;
}

static class ToDoHolder {
    TextView rowTitle;
    TextView rowDesc;
    TextView rowDate;
    CheckBox rowIsDone;
}
}

下面是我的 MainActivity 类,它从“AddToDoTask”类中获取单行元素的详细信息。

public class MainActivity extends AppCompatActivity {
private final int requestCode = 1;
ArrayList<ToDoTask> lista = new ArrayList<>();
ToDoAdapter adapter = null;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Button button = (Button) findViewById(R.id.buttonAdd);
    ListView listView = (ListView) findViewById(R.id.listView);

    adapter = new ToDoAdapter(this, R.layout.row, lista);
    listView.setAdapter(adapter);

    button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Intent intent = new Intent(getApplicationContext(), AddToDoTask.class);
            startActivityForResult(intent, requestCode);
        }
    });

}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    String title, description, date;
    Boolean isDone;

    if (requestCode == 1) {
        if (null != data) {
            title = data.getStringExtra("title");
            description = data.getStringExtra("description");
            date = data.getStringExtra("date");
            isDone = data.getBooleanExtra("done", false);

            lista.add(new ToDoTask(title, description, date, isDone));
            adapter.notifyDataSetChanged();
        }
    }
}

}

【问题讨论】:

标签: java android listview checkbox adapter


【解决方案1】:
public class ToDoAdapter extends ArrayAdapter<ToDoTask> {
    private ArrayList<ToDoTask> objects;
    private Context context;
    private int resource;
    private SparseBooleanArray checkedPositions = new SparseBooleanArray();

    public ToDoAdapter(@NonNull Context context, @LayoutRes int resource, @NonNull ArrayList<ToDoTask> objects) {
        super(context, resource, objects);
        this.objects = objects;
        this.context = context;
        this.resource = resource;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ToDoHolder toDoHolder;
        if (convertView == null) {
            LayoutInflater layoutInflater = LayoutInflater.from(context);
            convertView = layoutInflater.inflate(R.layout.row, parent, false);
            toDoHolder = new ToDoHolder();
            toDoHolder.rowTitle = (TextView) convertView.findViewById(R.id.rowTitle);
            toDoHolder.rowDesc = (TextView) convertView.findViewById(R.id.rowDesc);
            toDoHolder.rowDate = (TextView) convertView.findViewById(R.id.rowDate);
            toDoHolder.rowIsDone = (CheckBox) convertView.findViewById(R.id.rowCheckBoxDone);
            convertView.setTag(toDoHolder);
        } else {
            toDoHolder = (ToDoHolder) convertView.getTag();
        }
        toDoHolder.rowTitle.setTag(position);
        toDoHolder.rowIsDone.setTag(convertView);
        toDoHolder.rowIsDone.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
                View view = (View) compoundButton.getTag();
                TextView title = (TextView) view.findViewById(R.id.rowTitle);
                int pos = (int) title.getTag();
                if (checked) {
                    checkedPositions.put(pos, true);
                    view.setBackgroundColor(Color.parseColor("#8FE370"));
                } else {
                    checkedPositions.put(pos, false);
                    view.setBackgroundColor(Color.WHITE);
                }
            }
        });
        ToDoTask object = objects.get(position);
        toDoHolder.rowTitle.setText(object.getTitle());
        toDoHolder.rowDesc.setText(object.getDescription());
        toDoHolder.rowDate.setText(object.getDate());
        toDoHolder.rowIsDone.setChecked(object.getDone() || checkedPositions.get(position));
        return convertView;
    }

    private class ToDoHolder {
        private TextView rowTitle;
        private TextView rowDesc;
        private TextView rowDate;
        private CheckBox rowIsDone;
    }
}

【讨论】:

  • 谢谢,它解决了添加新行的问题,但是现在当我添加新行时,前一个选中复选框的背景是白色而不是绿色。我假设我必须在其他情况下使用 getTag(),就像在“toDoHolder = (ToDoHolder) view.getTag();”中一样- 我对吗?如何在这个元素上使用 getTag?
  • 请把上面提到的代码从 if 条件中移出,然后粘贴到 DoHolder.rowIsDone.setChecked(object.getDone());
  • 您的意思是上面帖子中的整个代码?我做到了,但是当我添加新行时背景仍然从绿色变为白色。
  • 当我们添加新行时,为了更新数据,我们必须调用 notifyDataSetChanged() 方法。这将根据 ToDoTask 模型数据重置所有行,并且仅当 object.getDone() 为 true 时才会设置为绿色。如果你想保持手动检查状态,我们必须坚持检查位置,我已经修改了你的适配器,请看一下。
  • 我不知道为什么,但我不得不在 if/else 循环中交换背景颜色,我的意思是把颜色白色放在“checkedPositions.put(pos, true);”中现在一切正常。感谢您的努力和帮助,主题已解决。
【解决方案2】:

您必须在 row xml 文件中添加布局并将布局放入 toDoHolder 并更改布局背景颜色。您可以访问子视图,如

layout.findViewByID(int ID);

【讨论】:

    猜你喜欢
    • 2013-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-04
    • 1970-01-01
    • 1970-01-01
    • 2015-06-17
    • 2014-04-11
    相关资源
    最近更新 更多