How to select multiple checkboxes in a submenu on Android?

I have an options menu with the "Add / Remove" option, which, when clicked, displays a checklist. The problem with the code that I currently have is that you can only select one item at a time, and the menu disappears. I want to be able to check several items in the list at once and not disappear until the user touches a place in another place on the screen. How can i do this? Here is a general idea of โ€‹โ€‹what I have:

<?xml version="1.0" encoding="UTF-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/select_options" android:title="Add/Remove"> <menu> <group android:checkableBehavior="all"> <item android:id="@+id/A" android:checked="true" android:title="Option One" /> <item android:id="@+id/B" android:checked="true" android:title="Option Two" /> </group> </menu> </item> </menu> 

and

 @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.selection_menu, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item){ switch (item.getItemId()){ case R.id.A: item.setChecked(!item.isChecked()); return true; case R.id.B: item.setChecked(!item.isChecked()); return true; default: return super.onOptionsItemSelected(item); } } 
+7
source share
1 answer

Hi TheBeatlemaniac!

I honestly donโ€™t know if what you are looking for is feasible or not (EDIT: how you implement it, as a submenu), but I would do it like this:

Create an action that looks like a submenu that you want to display.

It may seem a little more complicated, but it is straightforward, and thus it will not disappear if you select / deselect an item and you can implement much more functionality.

Here is how I personally would do it:


  • Create a class to represent the submenu item. It should contain a string (description) and a logical value (to save if it is checked or not).
 public class SettingCheckBox implements Serializable { private static final long serialVersionUID = 1L; private static final String DEFAULT_DESCRIPTION = "N/A"; private final String description; private boolean checked; public String getDescription () { return description == null ? DEFAULT_DESCRIPTION : description; } public void setChecked ( final boolean checked ) { this.checked = checked; } public boolean getChecked () { return checked; } public SettingCheckBox ( final String description ) { this.description = description; } } 

As you can see, the class implements Serializable so that objects of this class can be transferred from one operation to another using intentions / packages.

  • Add the following to your current action: I assumed it was called MainActivity , so when you try it, replace MainActivity with the name of your activity).
 public static final String SETTING_CHECK_BOX = "SETTING_CHECK_BOX"; private ArrayList < SettingCheckBox > settingList; @Override public void onCreate(Bundle savedInstanceState) { // ... settingList = new ArrayList < SettingCheckBox > (); settingList.add ( new SettingCheckBox ( "Option A" ) ); settingList.add ( new SettingCheckBox ( "Option B" ) ); // ... add more items // restore any previously saved list if ( savedInstanceState != null ) { settingList = (ArrayList < SettingCheckBox >) savedInstanceState.getSerializable ( SETTING_CHECK_BOX ); } // ... } protected void onSaveInstanceState ( Bundle outState ) { super.onSaveInstanceState ( outState ); outState.putSerializable ( SETTING_CHECK_BOX , settingList ); } 

The list (ArrayList) is used to place all the elements of the parameter submenu using flags. As you can see, each SettingCheckBox object has a description and status (checked or not checked). By default, after creation, the state of the object is not marked. You must initialize the list inside the onCreate method.

The static and final variable SETTING_CHECK_BOX is used as a key to save / restore the contents of this list before / after recreating the activity (for example, to rotate the screen), and also to transfer the list of settings from activity to another. (explained later)

  • Delete the submenu so that the menu xml file looks like this:
 <?xml version="1.0" encoding="UTF-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/select_options" android:title="Add/Remove"> </item> </menu> 

There is no need for an additional menu, as you will perform an action that acts as one. Now, to associate a menu item with an activity that will display settings, you must use the onOptionsItemSelected method inside your current action, for example:

 @Override public boolean onOptionsItemSelected ( MenuItem menuItem ) { if ( menuItem.getItemId () == R.id.select_options ) { Intent intent = new Intent ( this , MyActivity_Settings.class ); intent.putExtra ( SETTING_CHECK_BOX , settingList ); startActivityForResult ( intent , 0 ); } } 

Settings activity is triggered for the result. This means that it behaves as a child activity and can return the result to its parent activity.

The list of settings is transferred to the settings using intent.

If the child activity completes and returns the parent activity data, the following method is called:

 protected void onActivityResult ( int requestCode , int resultCode , Intent data ) { if ( resultCode != RESULT_OK || data == null ) return; settingList = (ArrayList < SettingCheckBox >) data.getSerializableExtra ( SETTING_CHECK_BOX ); } 

You must make the child / settings action return a (new / changed) list of settings, and as shown above, the new list is set.

  • Create the following XML layout file called sub_menu:
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <ListView android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="wrap_content" > </ListView> </LinearLayout> 

This is a mock activity that will act as your submenu. This is actually an activity of the list and can contain as many parameters as possible (you simply add them to the list of arrays specified in your activity above).

  • Create the following XML layout file called sub_menu_item:
 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:gravity="center_vertical" > <TextView android:id="@+id/option_title" android:layout_width="0dip" android:layout_height="wrap_content" android:layout_weight="1" android:textAppearance="@android:style/TextAppearance.Medium" /> <CheckBox android:id="@+id/option_checkbox" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> 

This is the layout of each line in the list, there is a text view and a checkbox (as in the submenu that you already used).

  • Create a new class called MyActivity_Settings, which should contain the following:
 public class MyActivity_Settings extends ListActivity { private ArrayList < SettingCheckBox > settingList; @Override public void onCreate ( Bundle savedInstanceState ) { super.onCreate(savedInstanceState); setContentView ( R.layout.sub_menu ); setTitle ( "Add/Remove" ); settingList = getIntent ().getSerializableExtra ( MainActivity.SETTING_CHECK_BOX ); if ( savedInstanceState != null ) { settingList = (ArrayList < SettingCheckBox >) savedInstanceState.getSerializable ( MainActivity.SETTING_CHECK_BOX ); } setListAdapter ( new MyActivity_Settings_Adapter ( this , R.layout.item_layout , settingList ) ); } protected void onSaveInstanceState ( Bundle outState ) { super.onSaveInstanceState ( outState ); outState.putSerializable ( MainActivity.SETTING_CHECK_BOX , settingList ); } @Override public void finish () { setResult ( RESULT_OK , new Intent ().putExtra ( MainActivity.SETTING_CHECK_BOX , settingList ) ); super.finish (); } } class MyActivity_Settings_Adapter extends ArrayAdapter < SettingCheckBox > { private final LayoutInflater layoutInflater; private final int itemResourceId; // Holder pattern (used instead of findViewById for better performance) static class ViewHolder { public TextView title; public CheckBox checkBox; } // Constructor public MyActivity_Settings_Adapter ( ListActivity context, int itemResourceId , List < SettingCheckBox > options ) { super ( context , itemResourceId , options ); layoutInflater = context.getLayoutInflater (); this.itemResourceId = itemResourceId; } // Method called by the list view every time to display a row @Override public View getView ( int position , View convertView , ViewGroup parent ) { // Declare and initialize the row view View rowView = convertView; // Declare the row view holder ViewHolder viewHolder; // Check if an inflated view is provided if ( rowView == null ) { // A new view must be inflated rowView = layoutInflater.inflate ( itemResourceId , null ); // Declare and initialize a view holder viewHolder = new ViewHolder (); // Retrieve a reference to the row title viewHolder.title = (TextView) rowView.findViewById ( R.id.option_title ); // Retrieve a reference to the row check box viewHolder.checkBox = (CheckBox) rowView.findViewById ( R.id.option_checkbox ); // Store the view holder as tag rowView.setTag ( viewHolder ); } // End if else // An inflated view is already provided, retrieve the stored view holder viewHolder = (ViewHolder) rowView.getTag (); // Set the option title viewHolder.title.setText ( getItem ( position ).getDescription () ); // Set the option check box state viewHolder.checkBox.setChecked ( getItem ( position ).getChecked () ); // Assign a click listener to the checkbox viewHolder.checkBox.setOnClickListener( new OnClickListener() { public void onClick ( View checkBox ) { // Retrieve the stored view holder ViewHolder viewHolder = (ViewHolder) ((View) checkBox.getParent()).getTag(); // Update the option state getItem ( position ).setChecked ( ! getItem ( position ).getChecked () ); // Display the new option state viewHolder.checkBox.setChecked ( getItem ( position ).getChecked () ); } }); // Return the row view for display return rowView; } // End of getView } 

This class represents an action that will act as your submenu. As I said, this is list activity (and therefore should extend ListActivity). To display various parameters inside the list, you need an adapter (for this case, an array adapter is enough), which is the role of the MyActivity_Settings_Adapter class (which extends ArrayAdapter).

If the action of the list ends (the user presses the "Back" button or somewhere outside the operation, which is displayed as a dialog), it (action) returns to the parent action a new list of parameters with the new values โ€‹โ€‹marked.

The adapter will build each line to display a list. In addition, the adapter will assign a click listener for each flag, so if it is installed (or not installed), the option will be changed accordingly.

And if you click anywhere outside the submenu (or just click the "Back" button), the submenu will disappear, and the user's selection will be saved in a boolean array in your main action.

If you are not familiar with ListActivity and ArrayAdapter, this tutorial will help a lot!

  • Remember to add this to your Android manifest XML file (in the application tag):
  <activity android:name=".MyActivity_Settings" android:theme="@android:style/Theme.Dialog" /> 

The applicable theme (@android: style / Theme.Dialog) will make the activity look like a submenu.

Hope this helps! I tried and it works great! Try it and let me know what will happen.

+6
source

All Articles