Search code examples
androidandroid-layoutcustomizationandroid-alertdialogradiobuttonlist

Adding a CheckBox to a singlechoice set AlertDialog


I want to add a checkbox to this standard AlertDialog wiht a single choice list

new AlertDialog.Builder(this)
.setSingleChoiceItems(R.array.difficultyLevel_list, 1, new DialogInterface.OnClickListener() {
    @Override public void onClick(DialogInterface dialog, int which) { level = which; }
})
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {
    }
})
.setNegativeButton(android.R.string.cancel, null)
.show();

Right now as it is, it shows nicely:

enter image description here

I shifted to use custom layout:

<?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="vertical" >

    <CheckBox
        android:id="@+id/levels_keep"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:layout_marginTop="10dp"
        android:checked="false"
        android:text="@string/levels_keep" />

    <ListView
        android:id="@+id/levels_list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:entries="@array/difficultyLevel_list"
        android:choiceMode="singleChoice" />

</LinearLayout>

Using this code:

LayoutInflater inflater = getLayoutInflater();
final View customView = inflater.inflate(R.layout.dialog_levels, null);
final ListView list = (ListView) customView.findViewById(R.id.levels_list);
final CheckBox keep = (CheckBox) customView.findViewById(R.id.levels_keep);
// list.setSelected(level);
list.setItemChecked(level, true); // Marks the item as checked
list.setOnItemClickListener(new OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        level = position;
    }
});

new AlertDialog.Builder(this)
.setView(customView)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {
        CheckBox keep = (CheckBox) findViewById(R.id.levels_keep);
        if( keep.isChecked() ) {
            Context context = PlayersActivity.this;
            SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
            Editor editor = sp.edit();
            editor.putString(context.getString(R.string.pref_level_key), String.valueOf(level));
            editor.commit();
        }
    }
})
.setNegativeButton(android.R.string.cancel, null)
.show();

Which shows (the List is scrollable):

enter image description here

There are several things I cannot figure out:

  1. Why I don't see radio buttons on the list?
  2. How do I set a default checked item? (Edited the code with the solution)
  3. How do I listen to changes in the selection? (Edited the code, since I found how to do it)
  4. How can I add padding between the checkbox square and the checkbox text. I tried android:paddingLeft but is makes it worse, overlapping text and square. I tried android:drawablePadding to no effect.
  5. Why the theme has changed ? (no really important, just curious) Edit It seems that the theme colors are all messed up, when I click on an item its text color becomes black and "dissapear" into the row's background

Solution

  • Why I don't see radio buttons on the list?

    It appears that setting the android:entries attribute makes the ListView to create an ArrayAdapter using com.android.internal.R.layout.simple_list_item_1 as the layout. I don't know if that layout fully replicates the android.R.layout.simple_list_item_1 layout but if it does then it's just a TextView so no CheckBox is available.

    How do I set a default checked item?

    If what I said above is true, then remove the entries attribute and set the adapter for the *levels_list* ListView in code using android.R.layout.simple_list_item_single_choice as the row layout.

    How do I listen to changes in the selection?

    Set a OnItemClickListener on the ListView from the layout.

    How can I add padding between the checkbox square and the checkbox text. I tried android:paddingLeft but is makes it worse, overlapping text and square. I tried android:drawablePadding to no effect.

    Use a simple CheckBox and a TextView instead of just a CheckBox and you could place those as you please.

    Why the theme has changed ? (no really important, just curious)

    I'm not sure. First of all, as I said above the ListView uses a special layout(which I don't know how it's styled) and also you're using a custom view instead of the normal ListView content which again could be styled differently.

    If you just want a ChekcBox in the title, why not just set a custom title on the AlertDialog and continue to use setSingleChoiceItems?

    Edited by the OP with the solution

    I post the working code here, since it is definitely bases on Luksprog answer, and i want to mark it as the answer. This code was tested and works fine.

    LayoutInflater inflater = getLayoutInflater();
    final View customView = inflater.inflate(R.layout.dialog_levels, null);
    final ListView list = (ListView) customView.findViewById(R.id.levels_list);
    final CheckBox keep = (CheckBox) customView.findViewById(R.id.levels_keep);
    String [] items = getResources().getStringArray(R.array.difficultyLevel_list);
    ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_single_choice, items);
    list.setAdapter(adapter);
    list.setItemChecked(level, true);
    list.setOnItemClickListener(new OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            level = position;
        }
    });
    
    new AlertDialog.Builder(this)
    .setView(customView)
    .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            MyLog.w(TAG,"Level is " + level);
            if( keep.isChecked() ) {
                Context context = PlayersActivity.this;
                SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
                Editor editor = sp.edit();
                editor.putString(context.getString(R.string.pref_level_key), String.valueOf(level));
                editor.commit();
            }
        }
    })
    .setNegativeButton(android.R.string.cancel, null)
    .show();