I have an options menu with an "Add/Remove" option that, when clicked, shows a checkable list. 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 multiple items in the list at once, and for it not to disappear until the user touches a spot elsewhere on the screen. How can I do this? Here's the 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);
}
}
Simply check or uncheck multiple checkboxes at a time by clicking and dragging. Allows you to check multiple checkboxes quickly by CLICKING & DRAGGING or even quicker with an ALT+CLICK & DRAG area select.
By default, the android CheckBox will be in the OFF (Unchecked) state. We can change the default state of CheckBox by using android:checked attribute. In case, if we want to change the state of CheckBox to ON (Checked), then we need to set android:checked = “true” in our XML layout file.
Hello TheBeatlemaniac !
I honestly don't know if what you are seeking for is doable or not ( EDIT : in the way you are implementing it, as a sub menu ), but I would have done it this way:
Create an activity that looks like the sub menu you want to display.
It might seem a little bit more complicated but it is straight forward and in this manner, it will not disappear if you select / deselect an item, and you can implement much more functionality.
Here's how I would have personally done it:
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 that class can be passed from an activity to another using intents/bundles.
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 host all your setting sub menu items with the check boxes. As you can see, each SettingCheckBox object has a description and a state (checked or unchecked). By default, once create, the object state is unchecked. You should initialize the list inside the onCreate method.
The static and final variable SETTING_CHECK_BOX is used as key to save/restore the content of that list before/after activity recreations (like a screen rotation), and also to pass the settings list from an activity to another. (explained later on)
<?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>
No need for the sub menu anymore since you will be implementing an activity that acts like one. Now, to link the menu item to the activity that will display the settings, you should use the onOptionsItemSelected method inside your current activity like this :
@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 );
}
}
The settings activity is started for a result. It means like it behaves as a child activity, and can return a result to its parent activity.
The settings list is passed to the settings activity via the intent.
If the child activity ends and returns data to the parent activity, 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 should make the child / settings activity return the (new/modified) list of settings, and as demonstrated above, the new list is set.
<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 the layout of the activity that will act as your sub menu. It is actually a list activity, and can hold as many options as you want (you just add them in the array list declared in your activity above).
<?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 row in the list, there is a text view and check box ( just like the sub menu you were already using).
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 the activity that will act as your sub menu. As I previously said, it is a List Activity (and hence should extend ListActivity). In order to display the various options inside the list, you need an adapter (array adapter is sufficient for this case), that's the role of the MyActivity_Settings_Adapter class (that extends ArrayAdapter ).
If the list activity finishes (the user clicks on the back button, or anywhere outside the activity which is displayed as a dialog), it (the activity) returns to the parent activity the new list of options with the new checked values.
The adapter will build each row for the list to display. In addition, the adapter will assign a click listener for every check box, so that if checked (or unchecked) the option will be modified accordingly.
And if you click anywhere outside the sub menu (or simply press on the back button), the sub menu will disappear, and the user selections are preserved in the boolean array in your main activity.
If you are not familiar with ListActivity and ArrayAdapter, this tutorial would help a lot !
<activity android:name=".MyActivity_Settings"
android:theme="@android:style/Theme.Dialog" />
The theme applied (@android:style/Theme.Dialog) will make the activity look like a sub menu.
Hope it helps ! I tried it and it works perfectly ! Try it and let me know what happens.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With