Custom Listview containing checkedtextview

61 views Asked by At

I implement custom listview containing a checked textview. My wish is to change the state of the checkbox on click, but it seems not to be simple, as I thought it would be. Additionally I would like to check the checkboxes of items, that are stored in database, how could it be done? At the moment I have an activity which shows the elements, handles the click on the checkbox (not the list item!), but can“t change the checkbox status by items stored in database.

This is my custom list item:

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:padding="5dp">

    <CheckedTextView
            android:id="@+id/name"
            android:layout_width="409dp"
            android:layout_height="30dp"
            android:checkMark="?android:attr/listChoiceIndicatorMultiple"
            android:paddingStart="5dp"
            android:textSize="20sp"
            android:textStyle="bold"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

    <TextView
            android:id="@+id/type"
            android:layout_width="409dp"
            android:layout_height="34dp"
            android:paddingStart="5dp"
            android:textSize="18sp"
            android:textStyle="italic"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/name" />

</androidx.constraintlayout.widget.ConstraintLayout>

This is my adapter:

public class CustomAdapter extends BaseAdapter
{
    private List<CustomElement> elems;
    private LayoutInflater inflater;

    public HueBulbAdapter(Context ctx, List<CustomElement> elems)
    {
        this.elems = elems;
        inflater = LayoutInflater.from(ctx);
    }

    @Override
    public int getCount()
    {
        return elems.size();
    }

    @Override
    public Object getItem(int position)
    {
        return null;
    }

    @Override
    public long getItemId(int position)
    {
        return 0;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent)
    {
        ConstraintLayout result = (ConstraintLayout) inflater.inflate(R.layout.custom_elems, parent, false);
        CheckedTextView name = result.findViewById(R.id.name);
        TextView type = result.findViewById(R.id.type);
        CustomElement elem = elems.get(position);
        name.setText(elem.getName());
        type.setText(elem.getType());
        result.setTag(position);
        toggle(name);
        return result;
    }

    private void toggle(CheckedTextView ctv) {
        ctv.setOnClickListener(v -> {
            ctv.setChecked(!ctv.isChecked());
        });
    }
}

And this is my activity:

[...]
elemsView.setOnItemClickListener((parent, view, position, id) ->
        {
            if (!selected.containsKey(elemList.get(position).getName()))
            {
                selected.put(elemList.get(position).getName(), elemList.get(position));
            } else
            {
                selected.remove(elemList.get(position).getName());
            }
        });
[...]

Maybe I am using wrong components to reach my target? Any Ideas how to do it this way or in a better way?

Thanks for your help!

1

There are 1 answers

0
lurker0152 On

Few suggestions:

  1. Add a boolean variable to the CustomElement model to track if item is checked or not checked. Add private boolean isChecked; and generate getter and setter for it.

  2. In adapter class, use public Object getItem(int position) to return item in list, and not null. Change to return elems.get(position);

  3. In adapter class, replace toggle(name) with:

    name.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        elem.setChecked(!elem.isChecked());  // toggle
        name.setChecked(elem.isChecked());
      }
    });
    
  4. In your activity class, to access the updated list, use this:

    for (int i = 0; i < mAdapter.getCount(); i++) {
      CustomElement element = (CustomElement) mAdapter.getItem(i);
      if (element.isChecked()) {...} else {...}
    }
    
  5. Optional. Search and implement ViewHolder Pattern in adapter class to improve the loading speed of ListView items.