CustomAdapter - CheckedTextView

556 Views Asked by At

I have a problem with "remembering" states of Checkboxes in CheckTextView. Now when I click, it changes the state but on different CheckBox.

class CustomAdapterSmartwatch extends ArrayAdapter<String> {


static class ViewHolder {
    protected CheckedTextView cTextView;
}

ViewHolder holder;


public CustomAdapterSmartwatch(Context context, ArrayList<String> variables) {
    super(context,R.layout.row_smartwatch_resources,variables);
}

@NonNull
@Override
public View getView(int position, View convertView, ViewGroup parent) {
    if (convertView == null) {
        holder = new ViewHolder();
        LayoutInflater smartwatchinflater = LayoutInflater.from(getContext());
        convertView = smartwatchinflater.inflate(R.layout.row_smartwatch_resources,parent,false);
        holder.cTextView = (CheckedTextView) convertView.findViewById(R.id.row_smartwatch_checked);
        convertView.setTag(holder);
    } else {
        holder = (ViewHolder) convertView.getTag();
    }

    holder.cTextView.setText(getItem(position));

    holder.cTextView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (holder.cTextView.isChecked()) {
                holder.cTextView.setChecked(false);
            } else {
                holder.cTextView.setChecked(true);
            }
        }
    });

    return convertView;
}

}

Now i'm trying to figure out with using Holder but i heard that it's possible to use SparseBooleanArray. Can someone explain how to make it works?

EDIT 1 Ok, I have ListView which is controlled by CustomAdapter. That adapter contains only 1 item (CheckedTextView). The problem is that after scrolling these checkedboxes don't remember their state. I saw your answer with explanation but now after clicking any "CheckedTextView", the state of their checkbox doesn't change.

EDIT 2

    @NonNull
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    if (convertView == null) {
        holder = new ViewHolder();
        LayoutInflater smartwatchinflater = LayoutInflater.from(getContext());
        convertView = smartwatchinflater.inflate(R.layout.row_smartwatch_resources,parent,false);
        holder.cTextView = (CheckedTextView) convertView.findViewById(R.id.row_smartwatch_checked);
        convertView.setTag(holder);
    } else {
        holder = (ViewHolder) convertView.getTag();
    }

    holder.cTextView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Log.d("MainActivity","Position = " + position);
            CheckedTextView checkedText = (CheckedTextView) v;
            checkedState.put(position, !checkedText.isChecked());

            Log.d("MainActivity","State = " + checkedState.get(position));

        }
    });

    holder.cTextView.setText(getItem(position));
    holder.cTextView.setChecked(checkedState.get(position));

    return convertView;
}

EDIT 3

class CustomAdapterSmartwatch extends ArrayAdapter<String> {

public SparseBooleanArray checkedState = new SparseBooleanArray();
private CheckedTextView cTextView;


public CustomAdapterSmartwatch(Context context, ArrayList<String> variables) {
    super(context,R.layout.row_smartwatch_resources,variables);
}

@NonNull
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    LayoutInflater smartwatchinflater = LayoutInflater.from(getContext());
    convertView = smartwatchinflater.inflate(R.layout.row_smartwatch_resources,parent,false);
    cTextView = (CheckedTextView) convertView.findViewById(R.id.row_smartwatch_checked);

    cTextView.setText(getItem(position));
    cTextView.setChecked(checkedState.get(position));

    cTextView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Log.d("MainActivity","Position = " + position);
            CheckedTextView checkedText = (CheckedTextView) v;
            checkedText.toggle();

            if (checkedText.isChecked())
                checkedState.put(position,true);
            else
                checkedState.delete(position);
            Log.d("MainActivity","State = " + checkedState.get(position));

        }
    });
    return convertView;
}

}

3

There are 3 best solutions below

13
Code-Apprentice On BEST ANSWER

You have to keep a boolean flag for each CheckTextView. This can be an array, List, or SparseBooleanArray. The data structure you choose should be a field of your adapter:

class CustomAdapterSmartwatch extends ArrayAdapter<String> {
    private SparseBooleanArray checkedState = new SparseBooleanArray();

    // ...
}

You do not want to put it in the holder because the holder is retired only fr visible rows. On the other hand, you want to maintain the checked state for every row, visible or not.

Now, you set the stored checked state when the user clicks on a CheckedTextView:

@NonNull
@Override
public View getView(int position, View convertView, ViewGroup parent) {
    // ...

    holder.cTextView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            CheckedTextView checkedText = (CheckedTextView)v;
            checkedState.put(position, checkedText.isChecked());
        }
    });
}

And you restore the checked state whenever you inflate a view or reuse one from a holder:

@NonNull
@Override
public View getView(int position, View convertView, ViewGroup parent) {
    // ...

    holder.cTextView.setText(getItem(position));
    holder.cTextView.setChecked(checkedState.get(position));

    // ...
}
5
Jagruttam Panchal On

Replace your code with following update:

class CustomAdapterSmartwatch extends ArrayAdapter<CustomAdapterSmartwatch.MyPojo> {

    class MyPojo {
        boolean checked;
        String data;

        public boolean isChecked() {
            return checked;
        }

        public void setChecked(boolean checked) {
            this.checked = checked;
        }

        public String getData() {
            return data;
        }

        public void setData(String data) {
            this.data = data;
        }
    }

    static class ViewHolder {
        protected CheckedTextView cTextView;
    }

    ViewHolder holder;


    public CustomAdapterSmartwatch(Context context, ArrayList<MyPojo> variables) {
        super(context, R.layout.row_smartwatch_resources, variables);
    }

    @Nullable
    @Override
    public MyPojo getItem(int position) {
        return super.getItem(position);
    }

    @NonNull
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if (convertView == null) {
            holder = new ViewHolder();
            LayoutInflater smartwatchinflater = LayoutInflater.from(getContext());
            convertView = smartwatchinflater.inflate(R.layout.row_smartwatch_resources,parent,false);
            holder.cTextView = (CheckedTextView) convertView.findViewById(R.id.row_smartwatch_checked);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        final MyPojo item = getItem(position);

        holder.cTextView.setText(item.getData());
        holder.cTextView.setChecked(item.isChecked());

        holder.cTextView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                boolean nextStatus = !item.isChecked();
                item.setChecked(nextStatus);
                holder.cTextView.setChecked(nextStatus);
            }
        });

        return convertView;
    }
}
1
phoenix On

You can simply use the view in onClick() method itself.

holder.cTextView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if(v instanceOf CheckedTextView) {
                CheckedTextView c = (CheckedTextView) v;
                c.setChecked(!c.isChecked());
            }
        }
    });