Browse Source

Single choice and multi choice dialogs' callbacks were changed. They now return a boolean: when you enable alwaysCallSingleChoiceCallback or alwaysCallMultiChoiceCallback, you can return false to not allow selection. Also added alwaysCallSingleChoiceCallback to AlertDialogWrapper.Builder.

Aidan Follestad 10 years ago
parent
commit
1b24402bfe

+ 15 - 7
library/src/main/java/com/afollestad/materialdialogs/AlertDialogWrapper.java

@@ -39,7 +39,7 @@ public class AlertDialogWrapper {
             builder.autoDismiss(dismiss);
             return this;
         }
-        
+
         public Builder setMessage(@StringRes int messageId) {
             builder.content(messageId);
             return this;
@@ -243,6 +243,11 @@ public class AlertDialogWrapper {
             return this;
         }
 
+        public Builder alwaysCallSingleChoiceCallback() {
+            builder.alwaysCallSingleChoiceCallback();
+            return this;
+        }
+
         public Builder alwaysCallMultiChoiceCallback() {
             builder.alwaysCallMultiChoiceCallback();
             return this;
@@ -261,9 +266,9 @@ public class AlertDialogWrapper {
                 selectedIndicesArr = selectedIndices.toArray(new Integer[selectedIndices.size()]);
             }
 
-            builder.itemsCallbackMultiChoice(selectedIndicesArr, new MaterialDialog.ListCallbackMulti() {
+            builder.itemsCallbackMultiChoice(selectedIndicesArr, new MaterialDialog.ListCallbackMultiChoice() {
                 @Override
-                public void onSelection(MaterialDialog dialog, Integer[] which, CharSequence[] text) {
+                public boolean onSelection(MaterialDialog dialog, Integer[] which, CharSequence[] text) {
                     /* which is a list of selected indices */
                     List<Integer> whichList = Arrays.asList(which);
                     if (checkedItems != null) {
@@ -278,6 +283,7 @@ public class AlertDialogWrapper {
                             }
                         }
                     }
+                    return true;
                 }
             });
         }
@@ -292,10 +298,11 @@ public class AlertDialogWrapper {
          */
         public Builder setSingleChoiceItems(@NonNull String[] items, int checkedItem, final DialogInterface.OnClickListener listener) {
             builder.items(items);
-            builder.itemsCallbackSingleChoice(checkedItem, new MaterialDialog.ListCallback() {
+            builder.itemsCallbackSingleChoice(checkedItem, new MaterialDialog.ListCallbackSingleChoice() {
                 @Override
-                public void onSelection(MaterialDialog dialog, View itemView, int which, CharSequence text) {
+                public boolean onSelection(MaterialDialog dialog, View itemView, int which, CharSequence text) {
                     listener.onClick(dialog, which);
+                    return true;
                 }
             });
             return this;
@@ -311,10 +318,11 @@ public class AlertDialogWrapper {
          */
         public Builder setSingleChoiceItems(@ArrayRes int itemsId, int checkedItem, final DialogInterface.OnClickListener listener) {
             builder.items(itemsId);
-            builder.itemsCallbackSingleChoice(checkedItem, new MaterialDialog.ListCallback() {
+            builder.itemsCallbackSingleChoice(checkedItem, new MaterialDialog.ListCallbackSingleChoice() {
                 @Override
-                public void onSelection(MaterialDialog dialog, View itemView, int which, CharSequence text) {
+                public boolean onSelection(MaterialDialog dialog, View itemView, int which, CharSequence text) {
                     listener.onClick(dialog, which);
+                    return true;
                 }
             });
             return this;

+ 107 - 67
library/src/main/java/com/afollestad/materialdialogs/MaterialDialog.java

@@ -56,6 +56,7 @@ import com.afollestad.materialdialogs.util.TypefaceHelper;
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -247,7 +248,7 @@ public class MaterialDialog extends DialogBase implements View.OnClickListener,
             invalidateCustomViewAssociations();
         }
 
-        if (mBuilder.listCallbackMulti != null)
+        if (mBuilder.listCallbackMultiChoice != null)
             selectedIndicesList = new ArrayList<>();
 
         boolean adapterProvided = mBuilder.adapter != null;
@@ -257,9 +258,9 @@ public class MaterialDialog extends DialogBase implements View.OnClickListener,
 
             if (!adapterProvided) {
                 // Determine list type
-                if (mBuilder.listCallbackSingle != null) {
+                if (mBuilder.listCallbackSingleChoice != null) {
                     listType = ListType.SINGLE;
-                } else if (mBuilder.listCallbackMulti != null) {
+                } else if (mBuilder.listCallbackMultiChoice != null) {
                     listType = ListType.MULTI;
                     if (mBuilder.selectedIndices != null) {
                         selectedIndicesList = new ArrayList<>(Arrays.asList(mBuilder.selectedIndices));
@@ -628,33 +629,68 @@ public class MaterialDialog extends DialogBase implements View.OnClickListener,
 
     @Override
     public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-        if (listType != null) {
-            // MaterialDialogAdapter, used for built-in adapters
+        if (mBuilder.listCallbackCustom != null) {
+            // Custom adapter
+            CharSequence text = null;
+            if (view instanceof TextView)
+                text = ((TextView) view).getText();
+            mBuilder.listCallbackCustom.onSelection(this, view, position, text);
+        } else if (listType == null || listType == ListType.REGULAR) {
+            // Default adapter, non choice mode
+            if (mBuilder.autoDismiss) {
+                // If auto dismiss is enabled, dismiss the dialog when a list item is selected
+                dismiss();
+            }
+            mBuilder.listCallback.onSelection(this, view, position, mBuilder.items[position]);
+        } else {
+            // Default adapter, choice mode
             if (listType == ListType.MULTI) {
-                // Keep our selected items up to date
-                boolean isChecked = !((CheckBox) view.findViewById(R.id.control)).isChecked();  // Inverted because the view's click listener is called before the check is toggled
-                boolean previouslySelected = selectedIndicesList.contains(position);
-                if (isChecked) {
-                    if (!previouslySelected) {
-                        selectedIndicesList.add(position);
+                final boolean shouldBeChecked = !selectedIndicesList.contains(Integer.valueOf(position));
+                final CheckBox cb = (CheckBox) ((LinearLayout) view).getChildAt(0);
+                if (shouldBeChecked) {
+                    // Add the selection to the states first so the callback includes it (when alwaysCallMultiChoiceCallback)
+                    selectedIndicesList.add(position);
+                    if (mBuilder.alwaysCallMultiChoiceCallback) {
+                        // If the checkbox wasn't previously selected, and the callback returns true, add it to the states and check it
+                        if (sendMultichoiceCallback()) {
+                            cb.setChecked(true);
+                        } else {
+                            // The callback cancelled selection, remove it from the states
+                            selectedIndicesList.remove(Integer.valueOf(position));
+                        }
+                    } else {
+                        // The callback was not used to check if selection is allowed, just select it
+                        cb.setChecked(true);
                     }
-                } else if (previouslySelected) {
+                } else {
+                    // The checkbox was unchecked
                     selectedIndicesList.remove(Integer.valueOf(position));
+                    cb.setChecked(false);
                 }
             } else if (listType == ListType.SINGLE) {
-                // Keep our selected item up to date
-                if (mBuilder.selectedIndex != position) {
+                boolean allowSelection = true;
+                if (mBuilder.autoDismiss && mBuilder.positiveText == null) {
+                    // If auto dismiss is enabled, and no action button is visible to approve the selection, dismiss the dialog
+                    dismiss();
+                    // Don't allow the selection to be updated since the dialog is being dismissed anyways
+                    allowSelection = false;
+                    sendSingleChoiceCallback(view);
+                } else if (mBuilder.alwaysCallSingleChoiceCallback) {
+                    int oldSelected = mBuilder.selectedIndex;
+                    // Temporarily set the new index so the callback uses the right one
+                    mBuilder.selectedIndex = position;
+                    // Only allow the radio button to be checked if the callback returns true
+                    allowSelection = sendSingleChoiceCallback(view);
+                    // Restore the old selected index, so the state is updated below
+                    mBuilder.selectedIndex = oldSelected;
+                }
+                // Update the checked states
+                if (allowSelection && mBuilder.selectedIndex != position) {
                     mBuilder.selectedIndex = position;
                     ((MaterialDialogAdapter) mBuilder.adapter).notifyDataSetChanged();
                 }
             }
-            onClick(view);
-        } else if (mBuilder.listCallbackCustom != null) {
-            // Custom adapter
-            CharSequence text = null;
-            if (view instanceof TextView)
-                text = ((TextView) view).getText();
-            mBuilder.listCallbackCustom.onSelection(this, view, position, text);
+
         }
     }
 
@@ -842,20 +878,21 @@ public class MaterialDialog extends DialogBase implements View.OnClickListener,
         return true;
     }
 
-    private void sendSingleChoiceCallback(View v) {
+    private boolean sendSingleChoiceCallback(View v) {
         CharSequence text = null;
         if (mBuilder.selectedIndex >= 0) {
             text = mBuilder.items[mBuilder.selectedIndex];
         }
-        mBuilder.listCallbackSingle.onSelection(this, v, mBuilder.selectedIndex, text);
+        return mBuilder.listCallbackSingleChoice.onSelection(this, v, mBuilder.selectedIndex, text);
     }
 
-    private void sendMultichoiceCallback() {
+    private boolean sendMultichoiceCallback() {
+        Collections.sort(selectedIndicesList); // make sure the indicies are in order
         List<CharSequence> selectedTitles = new ArrayList<>();
         for (Integer i : selectedIndicesList) {
             selectedTitles.add(mBuilder.items[i]);
         }
-        mBuilder.listCallbackMulti.onSelection(this,
+        return mBuilder.listCallbackMultiChoice.onSelection(this,
                 selectedIndicesList.toArray(new Integer[selectedIndicesList.size()]),
                 selectedTitles.toArray(new CharSequence[selectedTitles.size()]));
     }
@@ -867,9 +904,9 @@ public class MaterialDialog extends DialogBase implements View.OnClickListener,
             case POSITIVE: {
                 if (mBuilder.callback != null)
                     mBuilder.callback.onPositive(this);
-                if (mBuilder.listCallbackSingle != null)
+                if (mBuilder.listCallbackSingleChoice != null)
                     sendSingleChoiceCallback(v);
-                if (mBuilder.listCallbackMulti != null)
+                if (mBuilder.listCallbackMultiChoice != null)
                     sendMultichoiceCallback();
                 if (mBuilder.autoDismiss) dismiss();
                 break;
@@ -886,32 +923,6 @@ public class MaterialDialog extends DialogBase implements View.OnClickListener,
                 if (mBuilder.autoDismiss) dismiss();
                 break;
             }
-            default: {
-                String[] split = tag.split(":");
-                int index = Integer.parseInt(split[0]);
-                if (mBuilder.listCallback != null) {
-                    if (mBuilder.autoDismiss)
-                        dismiss();
-                    mBuilder.listCallback.onSelection(this, v, index, split[1]);
-                } else if (mBuilder.listCallbackSingle != null) {
-                    RadioButton cb = (RadioButton) ((LinearLayout) v).getChildAt(0);
-                    if (!cb.isChecked())
-                        cb.setChecked(true);
-                    if (mBuilder.autoDismiss && mBuilder.positiveText == null) {
-                        dismiss();
-                        sendSingleChoiceCallback(v);
-                    } else if (mBuilder.alwaysCallSingleChoiceCallback) {
-                        sendSingleChoiceCallback(v);
-                    }
-                } else if (mBuilder.listCallbackMulti != null) {
-                    CheckBox cb = (CheckBox) ((LinearLayout) v).getChildAt(0);
-                    cb.setChecked(!cb.isChecked());
-                    if (mBuilder.alwaysCallMultiChoiceCallback) {
-                        sendMultichoiceCallback();
-                    }
-                } else if (mBuilder.autoDismiss) dismiss();
-                break;
-            }
         }
     }
 
@@ -939,8 +950,8 @@ public class MaterialDialog extends DialogBase implements View.OnClickListener,
         protected int neutralColor;
         protected ButtonCallback callback;
         protected ListCallback listCallback;
-        protected ListCallback listCallbackSingle;
-        protected ListCallbackMulti listCallbackMulti;
+        protected ListCallbackSingleChoice listCallbackSingleChoice;
+        protected ListCallbackMultiChoice listCallbackMultiChoice;
         protected ListCallback listCallbackCustom;
         protected boolean alwaysCallMultiChoiceCallback = false;
         protected boolean alwaysCallSingleChoiceCallback = false;
@@ -1201,8 +1212,8 @@ public class MaterialDialog extends DialogBase implements View.OnClickListener,
 
         public Builder itemsCallback(@NonNull ListCallback callback) {
             this.listCallback = callback;
-            this.listCallbackSingle = null;
-            this.listCallbackMulti = null;
+            this.listCallbackSingleChoice = null;
+            this.listCallbackMultiChoice = null;
             return this;
         }
 
@@ -1214,11 +1225,11 @@ public class MaterialDialog extends DialogBase implements View.OnClickListener,
          * @param callback      The callback that will be called when the presses the positive button.
          * @return The Builder instance so you can chain calls to it.
          */
-        public Builder itemsCallbackSingleChoice(int selectedIndex, @NonNull ListCallback callback) {
+        public Builder itemsCallbackSingleChoice(int selectedIndex, @NonNull ListCallbackSingleChoice callback) {
             this.selectedIndex = selectedIndex;
             this.listCallback = null;
-            this.listCallbackSingle = callback;
-            this.listCallbackMulti = null;
+            this.listCallbackSingleChoice = callback;
+            this.listCallbackMultiChoice = null;
             return this;
         }
 
@@ -1242,11 +1253,11 @@ public class MaterialDialog extends DialogBase implements View.OnClickListener,
          * @param callback        The callback that will be called when the presses the positive button.
          * @return The Builder instance so you can chain calls to it.
          */
-        public Builder itemsCallbackMultiChoice(Integer[] selectedIndices, @NonNull ListCallbackMulti callback) {
+        public Builder itemsCallbackMultiChoice(Integer[] selectedIndices, @NonNull ListCallbackMultiChoice callback) {
             this.selectedIndices = selectedIndices;
             this.listCallback = null;
-            this.listCallbackSingle = null;
-            this.listCallbackMulti = callback;
+            this.listCallbackSingleChoice = null;
+            this.listCallbackMultiChoice = callback;
             return this;
         }
 
@@ -1834,7 +1845,7 @@ public class MaterialDialog extends DialogBase implements View.OnClickListener,
      * @return Currently selected index of a single choice list, or -1 if not showing a single choice list
      */
     public int getSelectedIndex() {
-        if (mBuilder.listCallbackSingle != null) {
+        if (mBuilder.listCallbackSingleChoice != null) {
             return mBuilder.selectedIndex;
         } else {
             return -1;
@@ -1848,7 +1859,7 @@ public class MaterialDialog extends DialogBase implements View.OnClickListener,
      */
     @Nullable
     public Integer[] getSelectedIndices() {
-        if (mBuilder.listCallbackMulti != null) {
+        if (mBuilder.listCallbackMultiChoice != null) {
             return selectedIndicesList.toArray(new Integer[selectedIndicesList.size()]);
         } else {
             return null;
@@ -1951,12 +1962,41 @@ public class MaterialDialog extends DialogBase implements View.OnClickListener,
         }
     }
 
+    /**
+     * A callback used for regular list dialogs.
+     */
     public interface ListCallback {
         void onSelection(MaterialDialog dialog, View itemView, int which, CharSequence text);
     }
 
-    public interface ListCallbackMulti {
-        void onSelection(MaterialDialog dialog, Integer[] which, CharSequence[] text);
+    /**
+     * A callback used for multi choice (check box) list dialogs.
+     */
+    public interface ListCallbackSingleChoice {
+        /**
+         * Return true to allow the radio button to be checked, if the alwaysCallSingleChoice() option is used.
+         *
+         * @param dialog The dialog of which a list item was selected.
+         * @param which  The index of the item that was selected.
+         * @param text   The text of the  item that was selected.
+         * @return True to allow the radio button to be selected.
+         */
+        boolean onSelection(MaterialDialog dialog, View itemView, int which, CharSequence text);
+    }
+
+    /**
+     * A callback used for multi choice (check box) list dialogs.
+     */
+    public interface ListCallbackMultiChoice {
+        /**
+         * Return true to allow the check box to be checked, if the alwaysCallSingleChoice() option is used.
+         *
+         * @param dialog The dialog of which a list item was selected.
+         * @param which  The indices of the items that were selected.
+         * @param text   The text of the items that were selected.
+         * @return True to allow the checkbox to be selected.
+         */
+        boolean onSelection(MaterialDialog dialog, Integer[] which, CharSequence[] text);
     }
 
     /**

+ 3 - 2
library/src/main/java/com/afollestad/materialdialogs/prefs/MaterialListPreference.java

@@ -55,9 +55,9 @@ public class MaterialListPreference extends ListPreference {
                 .icon(getDialogIcon())
                 .negativeText(getNegativeButtonText())
                 .items(getEntries())
-                .itemsCallbackSingleChoice(preselect, new MaterialDialog.ListCallback() {
+                .itemsCallbackSingleChoice(preselect, new MaterialDialog.ListCallbackSingleChoice() {
                     @Override
-                    public void onSelection(MaterialDialog dialog, View itemView, int which, CharSequence text) {
+                    public boolean onSelection(MaterialDialog dialog, View itemView, int which, CharSequence text) {
                         onClick(null, DialogInterface.BUTTON_POSITIVE);
                         dialog.dismiss();
                         if (which >= 0 && getEntryValues() != null) {
@@ -65,6 +65,7 @@ public class MaterialListPreference extends ListPreference {
                             if (callChangeListener(value) && isPersistent())
                                 setValue(value);
                         }
+                        return true;
                     }
                 });
 

+ 3 - 2
library/src/main/java/com/afollestad/materialdialogs/prefs/MaterialMultiSelectListPreference.java

@@ -65,9 +65,9 @@ public class MaterialMultiSelectListPreference extends MultiSelectListPreference
                 .negativeText(getNegativeButtonText())
                 .positiveText(getPositiveButtonText())
                 .items(getEntries())
-                .itemsCallbackMultiChoice(indicies.toArray(new Integer[indicies.size()]), new MaterialDialog.ListCallbackMulti() {
+                .itemsCallbackMultiChoice(indicies.toArray(new Integer[indicies.size()]), new MaterialDialog.ListCallbackMultiChoice() {
                     @Override
-                    public void onSelection(MaterialDialog dialog, Integer[] which, CharSequence[] text) {
+                    public boolean onSelection(MaterialDialog dialog, Integer[] which, CharSequence[] text) {
                         onClick(null, DialogInterface.BUTTON_POSITIVE);
                         dialog.dismiss();
                         final Set<String> values = new HashSet<>();
@@ -75,6 +75,7 @@ public class MaterialMultiSelectListPreference extends MultiSelectListPreference
                             values.add((String) s);
                         if (callChangeListener(values))
                             setValues(values);
+                        return true;
                     }
                 })
                 .dismissListener(this);

+ 4 - 1
sample/src/main/AndroidManifest.xml

@@ -1,4 +1,5 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
     package="com.afollestad.materialdialogssample">
 
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
@@ -8,7 +9,9 @@
         android:label="@string/app_name"
         android:icon="@drawable/ic_launcher"
         android:supportsRtl="true"
-        android:theme="@style/AppTheme">
+        android:theme="@style/AppTheme"
+        android:vmSafeMode="true"
+        tools:ignore="UnusedAttribute">
 
         <activity
             android:name=".MainActivity"

+ 63 - 18
sample/src/main/java/com/afollestad/materialdialogssample/MainActivity.java

@@ -6,6 +6,7 @@ import android.graphics.Color;
 import android.graphics.drawable.ColorDrawable;
 import android.os.Build;
 import android.os.Bundle;
+import android.support.annotation.StringRes;
 import android.support.v7.app.ActionBarActivity;
 import android.text.Editable;
 import android.text.Html;
@@ -34,6 +35,21 @@ import java.io.File;
  */
 public class MainActivity extends ActionBarActivity implements FolderSelectorDialog.FolderSelectCallback {
 
+    private Toast mToast;
+
+    private void showToast(String message) {
+        if (mToast != null) {
+            mToast.cancel();
+            mToast = null;
+        }
+        mToast = Toast.makeText(this, message, Toast.LENGTH_SHORT);
+        mToast.show();
+    }
+
+    private void showToast(@StringRes int message) {
+        showToast(getString(message));
+    }
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -123,6 +139,13 @@ public class MainActivity extends ActionBarActivity implements FolderSelectorDia
             }
         });
 
+        findViewById(R.id.multiChoiceLimited).setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                showMultiChoiceLimited();
+            }
+        });
+
         findViewById(R.id.customListItems).setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
@@ -261,17 +284,17 @@ public class MainActivity extends ActionBarActivity implements FolderSelectorDia
                 .callback(new MaterialDialog.ButtonCallback() {
                     @Override
                     public void onPositive(MaterialDialog dialog) {
-                        Toast.makeText(getApplicationContext(), "Positive!", Toast.LENGTH_SHORT).show();
+                        showToast("Positive!");
                     }
 
                     @Override
                     public void onNeutral(MaterialDialog dialog) {
-                        Toast.makeText(getApplicationContext(), "Neutral", Toast.LENGTH_SHORT).show();
+                        showToast("Neutral");
                     }
 
                     @Override
                     public void onNegative(MaterialDialog dialog) {
-                        Toast.makeText(getApplicationContext(), "Negative…", Toast.LENGTH_SHORT).show();
+                        showToast("Negative…");
                     }
                 })
                 .show();
@@ -284,7 +307,7 @@ public class MainActivity extends ActionBarActivity implements FolderSelectorDia
                 .itemsCallback(new MaterialDialog.ListCallback() {
                     @Override
                     public void onSelection(MaterialDialog dialog, View view, int which, CharSequence text) {
-                        Toast.makeText(getApplicationContext(), which + ": " + text, Toast.LENGTH_SHORT).show();
+                        showToast(which + ": " + text);
                     }
                 })
                 .show();
@@ -296,7 +319,7 @@ public class MainActivity extends ActionBarActivity implements FolderSelectorDia
                 .itemsCallback(new MaterialDialog.ListCallback() {
                     @Override
                     public void onSelection(MaterialDialog dialog, View view, int which, CharSequence text) {
-                        Toast.makeText(getApplicationContext(), which + ": " + text, Toast.LENGTH_SHORT).show();
+                        showToast(which + ": " + text);
                     }
                 })
                 .show();
@@ -309,7 +332,7 @@ public class MainActivity extends ActionBarActivity implements FolderSelectorDia
                 .itemsCallback(new MaterialDialog.ListCallback() {
                     @Override
                     public void onSelection(MaterialDialog dialog, View view, int which, CharSequence text) {
-                        Toast.makeText(getApplicationContext(), which + ": " + text, Toast.LENGTH_SHORT).show();
+                        showToast(which + ": " + text);
                     }
                 })
                 .positiveText(android.R.string.ok)
@@ -320,10 +343,11 @@ public class MainActivity extends ActionBarActivity implements FolderSelectorDia
         new MaterialDialog.Builder(this)
                 .title(R.string.socialNetworks)
                 .items(R.array.socialNetworks)
-                .itemsCallbackSingleChoice(2, new MaterialDialog.ListCallback() {
+                .itemsCallbackSingleChoice(2, new MaterialDialog.ListCallbackSingleChoice() {
                     @Override
-                    public void onSelection(MaterialDialog dialog, View view, int which, CharSequence text) {
-                        Toast.makeText(getApplicationContext(), which + ": " + text, Toast.LENGTH_SHORT).show();
+                    public boolean onSelection(MaterialDialog dialog, View view, int which, CharSequence text) {
+                        showToast(which + ": " + text);
+                        return true; // allow selection
                     }
                 })
                 .positiveText(R.string.choose)
@@ -334,9 +358,9 @@ public class MainActivity extends ActionBarActivity implements FolderSelectorDia
         new MaterialDialog.Builder(this)
                 .title(R.string.socialNetworks)
                 .items(R.array.socialNetworks)
-                .itemsCallbackMultiChoice(new Integer[]{1, 3}, new MaterialDialog.ListCallbackMulti() {
+                .itemsCallbackMultiChoice(new Integer[]{1, 3}, new MaterialDialog.ListCallbackMultiChoice() {
                     @Override
-                    public void onSelection(MaterialDialog dialog, Integer[] which, CharSequence[] text) {
+                    public boolean onSelection(MaterialDialog dialog, Integer[] which, CharSequence[] text) {
                         StringBuilder str = new StringBuilder();
                         for (int i = 0; i < which.length; i++) {
                             if (i > 0) str.append('\n');
@@ -344,13 +368,34 @@ public class MainActivity extends ActionBarActivity implements FolderSelectorDia
                             str.append(": ");
                             str.append(text[i]);
                         }
-                        Toast.makeText(getApplicationContext(), str.toString(), Toast.LENGTH_LONG).show();
+                        showToast(str.toString());
+                        return true; // allow selection
                     }
                 })
                 .positiveText(R.string.choose)
                 .show();
     }
 
+
+    private void showMultiChoiceLimited() {
+        new MaterialDialog.Builder(this)
+                .title(R.string.socialNetworks)
+                .items(R.array.socialNetworks)
+                .itemsCallbackMultiChoice(new Integer[]{1}, new MaterialDialog.ListCallbackMultiChoice() {
+                    @Override
+                    public boolean onSelection(MaterialDialog dialog, Integer[] which, CharSequence[] text) {
+                        boolean allowSelection = which.length <= 2; // limit selection to 2, the new selection is included in the which array
+                        if (!allowSelection) {
+                            showToast(R.string.selection_limit_reached);
+                        }
+                        return allowSelection;
+                    }
+                })
+                .positiveText(R.string.dismiss)
+                .alwaysCallMultiChoiceCallback() // the callback will always be called, to check if selection is still allowed
+                .show();
+    }
+
     private void showCustomList() {
         new MaterialDialog.Builder(this)
                 .title(R.string.socialNetworks)
@@ -358,7 +403,7 @@ public class MainActivity extends ActionBarActivity implements FolderSelectorDia
                         new MaterialDialog.ListCallback() {
                             @Override
                             public void onSelection(MaterialDialog dialog, View itemView, int which, CharSequence text) {
-                                Toast.makeText(MainActivity.this, "Clicked item " + which, Toast.LENGTH_SHORT).show();
+                                showToast("Clicked item " + which);
                             }
                         })
                 .show();
@@ -377,7 +422,7 @@ public class MainActivity extends ActionBarActivity implements FolderSelectorDia
                 .callback(new MaterialDialog.ButtonCallback() {
                     @Override
                     public void onPositive(MaterialDialog dialog) {
-                        Toast.makeText(getApplicationContext(), "Password: " + passwordInput.getText().toString(), Toast.LENGTH_SHORT).show();
+                        showToast("Password: " + passwordInput.getText().toString());
                     }
 
                     @Override
@@ -473,19 +518,19 @@ public class MainActivity extends ActionBarActivity implements FolderSelectorDia
                 .showListener(new DialogInterface.OnShowListener() {
                     @Override
                     public void onShow(DialogInterface dialog) {
-                        Toast.makeText(getApplicationContext(), "onShow", Toast.LENGTH_SHORT).show();
+                        showToast("onShow");
                     }
                 })
                 .cancelListener(new DialogInterface.OnCancelListener() {
                     @Override
                     public void onCancel(DialogInterface dialog) {
-                        Toast.makeText(getApplicationContext(), "onCancel", Toast.LENGTH_SHORT).show();
+                        showToast("onCancel");
                     }
                 })
                 .dismissListener(new DialogInterface.OnDismissListener() {
                     @Override
                     public void onDismiss(DialogInterface dialog) {
-                        Toast.makeText(getApplicationContext(), "onDismiss", Toast.LENGTH_SHORT).show();
+                        showToast("onDismiss");
                     }
                 })
                 .show();
@@ -562,6 +607,6 @@ public class MainActivity extends ActionBarActivity implements FolderSelectorDia
 
     @Override
     public void onFolderSelection(File folder) {
-        Toast.makeText(this, folder.getAbsolutePath(), Toast.LENGTH_SHORT).show();
+        showToast(folder.getAbsolutePath());
     }
 }

+ 7 - 0
sample/src/main/res/layout/activity_main.xml

@@ -93,6 +93,13 @@
             android:text="@string/multiChoice"
             android:layout_marginTop="@dimen/sample_button_spacing" />
 
+        <Button
+            android:id="@+id/multiChoiceLimited"
+            android:layout_width="match_parent"
+            android:layout_height="56dp"
+            android:text="@string/multiChoiceLimited"
+            android:layout_marginTop="@dimen/sample_button_spacing" />
+
         <Button
             android:id="@+id/customListItems"
             android:layout_width="match_parent"

+ 2 - 0
sample/src/main/res/values/strings.xml

@@ -139,5 +139,7 @@
     <string name="please_wait">Please wait…</string>
     <string name="done">Done!</string>
     <string name="optional_dialog_message">This is an optional dialog message.</string>
+    <string name="multiChoiceLimited">Multi Choice (Limit Selections)</string>
+    <string name="selection_limit_reached">Selection limit reached!</string>
 
 </resources>