How to use the Android checkbox _android

Source: Internet
Author: User
Tags gettext lockstate

0 and 1 are the basis of the computer, in mathematical logic, 0 and 1 represent two states, true and false. 0 and 1 seem simple, in fact, infinitely different. Today I'm going to talk about the Magic control checkbox with 0 and 1 features in the Android control.

Let's talk about the basic use of a checkbox. defined in XML.

<?xml version= "1.0" encoding= "Utf-8"?> <checkbox xmlns:android=
"http://schemas.android.com/apk/res/" Android "
 android:id=" @+id/cbx "
 android:layout_width=" wrap_content "
 android:layout_height=" Wrap_ Content "
 android:checked= false"/>

Use in activity

CheckBox CBX = (checkbox) Findviewbyid (R.ID.CBX);
Cbx.setoncheckedchangelistener (New Compoundbutton.oncheckedchangelistener () {
  @Override public
  Void OnCheckedChanged (Compoundbutton Buttonview, Boolean ischecked) {
   //do
  }
});

It's very simple. Note that the checkbox itself is a view that is displayed to the user, so we need to use the data to control its display. So, our checkbox is written in the activity.

Boolean ischecked= false;
CheckBox CBX = (checkbox) Findviewbyid (R.ID.CBX);
Cbx.setoncheckedchangelistener (New Compoundbutton.oncheckedchangelistener () {
  @Override public
  Void OnCheckedChanged (Compoundbutton Buttonview, Boolean ischecked) {
    if (ischecked) {//do something}else{
      //do something Else
    }
  }
);
Cbx.setchecked (ischecked);

In this way, when we change the data, the state of the view changes with the data. Note that the listener must be set before this setchecked to reflect the data to control the display of the view.

It's easy to use a checkbox alone, and then, in complex situations, the checkbox is used in conjunction with Listview/recyclerview (hereinafter referred to as LV/RV). This is not a simple question to consider, you know lv/ The number of views in the RV is not consistent with the data in the dataset, and the number of true views is much less than the number of data items in the dataset. Because the view on the screen in the list is reusable. Because of the LV/RV reuse mechanism, if we don't use the data to control the checkbox State, Will cause the checkbox's display to be garbled in the list. Let's say you only check the checkbox in the first item, and when the list rolls up, you'll see that the item below is also selected. Of course, I've had this situation when I was just learning Android, The key to the problem is to use the data to control the display of the view. So in Getview/onbindviewholder, we should write this.

Holder.cbx.setTag (item);
Holder.cbx.setOnCheckedChangeListener (New Compoundbutton.oncheckedchangelistener () {
  @Override
  public void OnCheckedChanged (Compoundbutton buttonview, Boolean ischecked) {
    Item item = (item) buttonview.gettag ();
    if (ischecked) {
      item.setcheckstate (true);
      Do something
    }else{
      item.setcheckstate (false);
      Do something Else}}
);
Cbx.setchecked (Item.getcheckstate ());

This method is basically correct, but we need to add a field to each data item to record the state, which is a bit too expensive. One is not necessary, and the second is that it causes local data structures to be inconsistent with the service-side structure. Typically, a checkbox is used in a list, It is obvious that the selected item is recorded, so you can understand that the selected status is given by the list, and the item itself should be stateless. So, if we refactor our code, Android provides us with a perfect data structure to solve this problem. You can use Sparsearray. , can also use Sparsebooleanarray, I now used to use Sparsebooleanarray,ok, please see the code

 private class Adapter extends recyclerview.adapter<recyclerview.viewholder>{Sp
  Arsebooleanarray mcheckstates=new Sparsebooleanarray ();
  @Override public Recyclerview.viewholder Oncreateviewholder (viewgroup parent, int viewtype) {//...}
    @Override public void Onbindviewholder (recyclerview.viewholder holder, int position) {Holder.cbx.setTag (position);  Holder.cbx.setOnCheckedChangeListener (New Compoundbutton.oncheckedchangelistener () {@Override public void
        OnCheckedChanged (Compoundbutton Buttonview, Boolean ischecked) {int pos = (int) buttonview.gettag ();
          if (ischecked) {mcheckstates.put (pos,true);
          Do something}else{mcheckstates.delete (POS);
    Do something Else}});
  Cbx.setchecked (Mcheckstates.get (Position,false));
@Override public int GetItemCount () {//...}}} 

The list is displayed correctly, and when you select the checkbox, the oncheckedchanged is automatically triggered to update the mcheckstates. At this point, if you want to use a program to select an item, then it's all right.

Mcheckstates.put (pos,true);
Adapter.notifydatasetchanged ();

If we want to get all the data items out of the list column, then with Sparsebooleanarray, this is very good to do.

Arraylist<item> selitems=new arraylist<> ();
for (int i=0;i < mcheckstates.size (); i++) {
  if (mcheckstates.valueat (i)) {
    Selitems.add ( Mcheckstates.keyat (i)));
  }

It is such a space and time saving, such code who does not like it. But it's not perfect. Because the checkbox this control is too easy to change, why say so, because even if you set it to disabled, it can still be selected, its oncheckedchanged will still trigger. So what do we do? Programmers think about the problem, Generally are the first to think the most stupid method, since oncheckedchanged still will trigger, then I will be in the Buttonview again set into a!ischeck not on the line.

Holder.cbx.setOnCheckedChangeListener (New Compoundbutton.oncheckedchangelistener () {
  @Override
  public void OnCheckedChanged (Compoundbutton buttonview, Boolean ischecked) {
    buttonview.setchecked (!ischecked);
    //...
  }
});

But in this case, it will call the Buttonview oncheckedchanged, in fact, Buttonview is outside the HOLDER.CBX, which will cause the death cycle. So if we use the CBX itself to change the state, then it must be locked.

Boolean lockstate=false;
Holder.cbx.setOnCheckedChangeListener (New Compoundbutton.oncheckedchangelistener () {
  @Override
  public void OnCheckedChanged (Compoundbutton buttonview, Boolean ischecked) {
   if (lockstate) return;
   Otherwise CBX change the state.
   Lockstate=true;
    Buttonview.setchecked (!ischecked);
    Lockstate=false;
    //...
  }
});

CBX lock is actually very common, for example, in OnCheckedChanged, you have to send a request, and the result of the request will update the CBX selected state, you have to use lockstate to directly change the status of the CBX, In order to facilitate the CBX of the state and mcheckstates inside the same.

Mada Mada, there is also a situation, if in oncheckedchanged, ischecked and Mcheckstates.get (POS), this will lead to what situation.

@Override public
void OnCheckedChanged (Compoundbutton buttonview, Boolean ischecked) {
 int pos = (int) Buttonview.gettag ();
  if (ischecked) {
 mcheckstates.put (pos,true);
   Do something
 }else{
   mcheckstates.delete (POS);
   Do something Else
 }
}

This will make your//do something two times, which is not necessary, and if your//do something is a network request, it will cause a bigger problem. Therefore, we need to filter this situation.

@Override public
void OnCheckedChanged (Compoundbutton buttonview, Boolean ischecked) {
  if (lockstate) return ;
  int pos = (int) buttonview.gettag ();
  if (Mcheckstates.get (pos,false) = = ischecked) return;
  if (ischecked) {
   mcheckstates.put (pos,true);
   Do something
  }else{
   mcheckstates.delete (POS);
   Do something Else
  }
}

Well, if you can connect the checkbox to the Sparsebooleanarray and take into account the lock and filter re-election, then you are using the checkbox. But the wonderful place I'm going to talk about is just beginning.

A list can only allow users to roll down, that is the simplest use, usually, because the list item is too many, the product will add the filtering function to the list item, but usually we do the filtering, will consider uses the spinner to do, but, the useful Android itself provides the spinner extensibility to be too bad, and is ugly , often lead to everyone rage, discard rather than. That's what I did. After my own fantastic thinking, I finally found a very clever mechanism to be very elegant implementation of the list of the filter. I'll share it with you now.

Next clear we today's another protagonist, that is Popupwindow (introduction), I first introduced the principle, first to the checkbox set Setoncheckedchangelistener, and then in oncheckedchanged inside, IsChecked branch in popupwindow,!ischecked, read the results in Popupwindow and update the list with the new filter criteria. OK, on the code:

Mainactivity:

public class Mainactivity extends Appcompatactivity {string[] filter_type_strs = {"Music", "book", "Movie"};
  CheckBox CBX;
  Private Boolean lockstate=false;
  int current_filter_type=0;
    @Override protected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate);
    Setcontentview (R.layout.activity_main);

    CBX = (CheckBox) Findviewbyid (R.ID.CBX);
    Cbx.settext (Filter_type_strs[current_filter_type]); Cbx.setoncheckedchangelistener (New Compoundbutton.oncheckedchangelistener () {@Override public void Oncheckedc
        Hanged (Compoundbutton Buttonview, Boolean ischecked) {if (lockstate) return; try {if (ischecked) {//here passed CBX as parameter Popupwindow pw = new FILTERLINEPW (Buttonview.getcon
            Text (), CBX, filter_type_strs);
          Pw.showasdropdown (CBX);
            else {//here Buttonview is CBX Integer pos = (integer) buttonview.gettag (); if (pos = null | | pos = = 1)Return

            Current_filter_type = pos;
          Toast.maketext (mainactivity.this, "search" +filter_type_strs[current_filter_type], Toast.length_short). Show ();
          The catch (NullPointerException e) {//Just in case lockstate = true;
          Buttonview.setchecked (!ischecked);
        Lockstate = false;

  }
      }
    });

 }
}

FILTERLINEPW:

public class FILTERLINEPW extends Popupwindow {radiogroup radiogroup;

  CheckBox OUTCBX;

  Generate IDs for dynamically generated radiobutton int[] Rbtids = {0, 1, 2}; Public FILTERLINEPW (context, CheckBox OUTCBX, string[] items) {Super (ViewGroup.LayoutParams.MATCH_PARENT, Vie
    WGroup.LayoutParams.MATCH_PARENT);
    View Contentview = layoutinflater.from (context). Inflate (R.layout.filter_line_popupwindow, NULL);
    Setcontentview (Contentview);
    Setfocusable (TRUE);
    Setoutsidetouchable (TRUE);
    THIS.OUTCBX = OUTCBX; Contentview.setonkeylistener (New View.onkeylistener () {@Override public boolean onkey (View v, int keycode, Ke
          Yevent event) {if (keycode = = Keyevent.keycode_back) {dismiss ();
        return true;
      return false;
    }
    }); Contentview.setfocusable (TRUE);
    This is very important contentview.setfocusableintouchmode (true); Contentview.setonclicklistener (New View.onclicklistener () {@Override public void onclicK (View v) {dismiss ();

    }
    });

  Init (context, contentview,items); } private void init (context context, View Contentview, string[] items) {/** * Initialize UI with incoming filter criteria * * Radio
    Group = (radiogroup) Contentview.findviewbyid (r.id.filter_layout);
    Radiogroup.clearcheck ();
    if (items = null) return; for (int i = 0; i < items.length i++) {RadioButton RadioButton = (RadioButton) layoutinflater.from (context).
      Flate (R.LAYOUT.LINE_POPUPWINDOW_RBT, NULL);
      Radiobutton.setid (Rbtids[i]);

      Radiobutton.settext (Items[i]);

      Radiogroup.addview (RadioButton,-1, Radiogroup.getlayoutparams ());
        if (Items[i].equals (Outcbx.gettext ())) {Outcbx.settag (i);
      Radiobutton.setchecked (TRUE);  } radiogroup.setoncheckedchangelistener (New Radiogroup.oncheckedchangelistener () {@Override public
      void OnCheckedChanged (radiogroup group, int checkedid) {dismiss ();
  }
    }); }//FocusVolume, rewrite dismiss (); @Override public void Dismiss () {if (OUTCBX!= null && outcbx.ischecked ()) {int id = radiogroup.getc
      Heckedradiobuttonid ();
      RadioButton RBT = (RadioButton) Radiogroup.findviewbyid (ID);
      Integer old_tag = (integer) outcbx.gettag ();
        if (Old_tag = = null) {Super.dismiss ();
      Return
        } if (Old_tag!= id) {Outcbx.settag (ID);
      Outcbx.settext (Rbt.gettext ());
      else {Outcbx.settag (-1);
    After execution, the negative branch outcbx.setchecked (false) in the oncheckedchanged in the mainactivity is executed;
  } Super.dismiss ();

 }
}

Effect Chart:

To explain briefly: in fact, the focus in the Popupwindow, mainactivity checkbox as a parameter passed to the Popupwindow. First, the user clicks on the Mainactivity checkbox, Then the ischecked branch will be executed, so that the Popupwindow is displayed to the user, so that the user operating environment to the Popupwindow inside, and other users to select a good selection of conditions, popupwindow the filter conditions to OUTCBX, The OUTCBX state is then changed to trigger the negative branch in the Mainactivity oncheckedchanged, which shows a toast, which can be used as a network request. Also, because the Popupwindow code does not block operations, So you're going to follow the next line of Super.dismiss () so you don't have to worry about Popupwindow shutdown in mainactivity. Finally, in the Mainactivity also joined the Try-catch to just in case, This mechanism is amazing. This mechanism separates the filtering operations from the activity, and it is really a software engineering practice for us to write the filter completely independent of the action.

Then I will open the other selection, but the most subtle principle lies in this simple example. After you finish reading, you might as well try yourself and feel it.

Well, the wonderful place is finished, is it not enjoyable ah. Well, finally, I'll get some more private food. CheckBox is inherited from TextView, many times, the button property of our checkbox does not have a large picture, which results in a small area of the Click CheckBox, so We need to use touchdelegate to enlarge the clickable area code of the checkbox:

public class Framelayoutcheckbox extends Framelayout {Compoundbutton cbx;
  Public Framelayoutcheckbox {Super (context);
  Public Framelayoutcheckbox (context, AttributeSet attrs) {Super (context, attrs); Framelayoutcheckbox (context, AttributeSet attrs, int defstyleattr) {Super (context, Attrs, defstyl
  EATTR); Private checkbox Findcheckbox (view view) {//recursive breadth First traversal find CheckBox-! I just want to relive the C arraylist<view> views =
    New Arraylist<> ();
    Views.add (view);
      while (!views.isempty ()) {View c = views.remove (0);
      if (c instanceof checkbox) {return (checkbox) C;
        else if (c instanceof viewgroup) {ViewGroup FA = (viewgroup) C;
        for (int i = 0; i < Fa.getchildcount (); i++) {Views.add (Fa.getchildat (i));
  }} return null;
    } @Override protected void Onfinishinflate () {super.onfinishinflate (); if (Getchildcount (> 0) {View child = Findcheckbox (this);
    if (child instanceof Compoundbutton) CBX = (Compoundbutton) child; } @Override protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {super.onmeasure (widthmeas
    Urespec, Heightmeasurespec);  if (CBX!= null) {Rect bounds = new Rect (Getpaddingleft (), Getpaddingtop (), getpaddingleft () + getmeasuredwidth () +
      Getpaddingright (), getpaddingtop () + getmeasuredheight () + getpaddingbottom ());
      Touchdelegate delegate = new Touchdelegate (bounds, CBX);
    Settouchdelegate (delegate);

 }
  }
}

This class can be used as a framelayout, we can put the checkbox inside, and then the checkbox's click area is the entire framelayout area. Of course this class also applies to RadioButton, But you can't put multiple Compoundbutton in there.

The above is the entire content of this article, I hope to help you learn.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.