Search code examples
androidcheckboxlayoutvisibilitylistadapter

Checkbox doesn't check first time after visibility change from GONE to VISIBLE


I have a CheckBox in my XML layout and its visibility set to GONE. Here is my layout:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:id="@+id/linearLayout1"
    android:layout_centerInParent="true">

    <CheckBox
        android:id="@+id/checkbox1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dip"
        android:visibility="gone"
        android:checked="false"/>

    <TextView
        android:id="@+id/title"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dip"
        android:layout_marginStart="10dip"
        android:layout_marginTop="10dip"
        android:layout_weight="20"
        android:ellipsize="end"
        android:maxLines="1"
        android:textAlignment="center"
        android:textColor="#000000"
        android:textSize="16sp"
        android:textStyle="bold" />
        <!--android:scrollHorizontally="true"-->
        <!--android:layout_alignParentLeft="true"-->
        <!--android:layout_alignParentStart="true"-->

    <Space
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="5" />

    <TextView
        android:id="@+id/body"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dip"
        android:layout_marginRight="8dip"
        android:layout_marginTop="10dip"
        android:layout_weight="35"
        android:ellipsize="end"
        android:maxLines="1"
        android:textAlignment="center"
        android:textColor="#000000"
        android:textSize="16sp" />
        <!--android:layout_alignParentRight="true"-->

    <ImageView
        android:id="@+id/Critical"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dip"
        android:layout_weight="10"
        android:textSize="16sp" />

    <ImageView
        android:id="@+id/state"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dip"
        android:layout_weight="10"
        android:textSize="16sp" />

</LinearLayout>

I set the visibility of the CheckBox to VISIBLE in my custom Adapter setOnLongClickListener. The problem happens on first time long click. For the first item of list when i set visibility to VISIBLE and then check one of the CheckBoxes, It isn't checked but my num_selected is incremented and set to one. Here is my CustomAdapter getView(the line with comments):

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

            final Holder holder = new Holder();
            final View rowView;
            rowView = inflater.inflate(R.layout.list_row_layout, parent, false);

            holder.tv1 = (TextView) rowView.findViewById(R.id.title);
            holder.tv2 = (TextView) rowView.findViewById(R.id.body);
            holder.cb = (CheckBox) rowView.findViewById(R.id.checkbox1);
            holder.iv = (ImageView) rowView.findViewById(R.id.state);
            holder.i2 = (ImageView) rowView.findViewById(R.id.Critical);
            holder.tv1.setText(Titles.get(position));
            holder.tv2.setText(Bodies.get(position));
            if (isSeen.get(position))
                holder.iv.setImageResource(R.mipmap.ic_done_all_black_24dp);
            else
                holder.iv.setImageResource(R.mipmap.ic_done_black_24dp);

            if (CList.get(position)) {
                holder.i2.setImageResource(R.mipmap.ic_priority_high_black_24dp);
            }

            if(num_selected > 0)
            {
                holder.cb.setVisibility(View.VISIBLE);
            }
            else
            {
                holder.cb.setVisibility(View.GONE);
            }

            rowView.setOnLongClickListener(new View.OnLongClickListener() {

                @Override
                public boolean onLongClick(View v) {

                    if((num_selected == 1)&(holder.cb.isChecked()))
                    {
                        holder.cb.setChecked(false);
                        num_selected--;
                        isSelected = false;
                    }
                    else
                        if(holder.cb.isChecked())
                    {
                        holder.cb.setChecked(false);
                        num_selected--;
                    }
                    else {
                        holder.cb.setVisibility(View.VISIBLE);  //  this is the line that change visibility with no problem
                        holder.cb.setChecked(true);             //  it seems this line doesn't work at all! 
                        num_selected++;                         //  this line is also increment it to 1
                    }

                    return true;
                }
            });

            return rowView;
        }

It seems that it needs delay to check a CheckBox. After that all CheckBoxes checked and unchecked properly.

Update: Also tried notifyDataSetChanged and holder.cb.invalidate(); and holder.cb.requestLayout(); with no luck. Also i forgot to say that my adapter is a ListAdapter.

Before LongClick :

before longclick

After LongClick :

after longclick


Solution

  • After running some test on my code, i figure out that that code makes Checkboxes disappear on scrolling. With little search i found the solution to my question and scrolling issue too. I define array of Boolean to store checked/unchecked CheckBoxes. I Define mCheckedState as class variable in my CustomAdapter and Update it in setOnLongClickListener accordingly:

    private final boolean[] mCheckedState; // **New Code**
    
    public View getView(final int position, View convertView, ViewGroup parent) {
    
            final Holder holder = new Holder();
            final View rowView;
            rowView = inflater.inflate(R.layout.list_row_layout, parent, false);
    
            holder.tv1 = (TextView) rowView.findViewById(R.id.title);
            holder.tv2 = (TextView) rowView.findViewById(R.id.body);
            holder.cb = (CheckBox) rowView.findViewById(R.id.checkbox1);
            holder.iv = (ImageView) rowView.findViewById(R.id.state);
            holder.i2 = (ImageView) rowView.findViewById(R.id.Critical);
            holder.tv1.setText(Titles.get(position));
            holder.tv2.setText(Bodies.get(position));
            if (isSeen.get(position))
                holder.iv.setImageResource(R.mipmap.ic_done_all_black_24dp);
            else
                holder.iv.setImageResource(R.mipmap.ic_done_black_24dp);
    
            if (CList.get(position)) {
                holder.i2.setImageResource(R.mipmap.ic_priority_high_black_24dp);
            }
    
            if(num_selected > 0)
            {
                holder.cb.setVisibility(View.VISIBLE);
            }
            else
            {
                holder.cb.setVisibility(View.GONE);
            }
    
            rowView.setOnLongClickListener(new View.OnLongClickListener() {
    
                @Override
                public boolean onLongClick(View v) {
    
                    if((num_selected == 1)&(holder.cb.isChecked()))
                    {
                        mCheckedState[position] = false;   // **New Code**
                        holder.cb.setChecked(false);
                        num_selected--;
                        isSelected = false;
                        notifyDataSetChanged();   // **New Code**
                    }
                    else
                        if(holder.cb.isChecked())
                    {
                        mCheckedState[position] = false;     // **New Code**
                        holder.cb.setChecked(false);     
                        notifyDataSetChanged();          // **New Code**
                        num_selected--;
                    }
                    else {
                        holder.cb.setVisibility(View.VISIBLE);  
                        notifyDataSetChanged();                 // **New Code**
                        holder.cb.setChecked(true);           
                        mCheckedState[position] = true;        // **New Code**
                        num_selected++;        
                    }
    
                    return true;
                }
            });
    
            holder.cb.setChecked(mCheckedState[position]);      // **New Code**
    
            return rowView;
        }
    

    I hope this helps other people having similar problems.