Welcome to the Treehouse Community
Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community!
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.
Start your free trial

Jourdan Dixon
4,752 PointsSpinner as Multi Select Drop Down List
I'm working to create an app where I'll need to make some spinners as drop down lists on Activity A where the user can multi select values. I'll then pass those values to Activity B where it will display a list filtered based on those values selected. That alone is turning into not an easy task as I'm trying to do it as clean as possible. But I also need each item in the list to have 2 values; an id and title (id to be unseen by the EU). The query will run based on the ids but the EU will only see the titles. Does ANYONE have a resource to help with something like this? I've looked it seems everywhere.
This part is much less important. Bread and butter, but if possible I'd like the app to remember what items were last selected. If that's too much then at least have default selected values (Select All).
I know I'm kind of asking a lot, but any resource help anyone can provide would be awesome.
2 Answers

Jourdan Dixon
4,752 PointsThanks. I actually ended up using bits from a few classes I found online and extending them to create Clear All and Select All buttons. I created this class:
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnMultiChoiceClickListener;
import android.util.AttributeSet;
import android.widget.ArrayAdapter;
import android.widget.SpinnerAdapter;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
public class MultiSelectSpinner extends android.support.v7.widget.AppCompatSpinner implements OnMultiChoiceClickListener {
private String[] _items = null;
private boolean[] _selection = null;
private final ArrayAdapter<String> _proxyAdapter;
public MultiSelectSpinner(Context context) {
super(context);
_proxyAdapter = new ArrayAdapter<>(context, android.R.layout.simple_spinner_item);
super.setAdapter(_proxyAdapter);
}
public MultiSelectSpinner(Context context, AttributeSet attrs) {
super(context, attrs);
_proxyAdapter = new ArrayAdapter<>(context, android.R.layout.simple_spinner_item);
super.setAdapter(_proxyAdapter);
}
@Override
public void onClick(DialogInterface dialog, int which, boolean isChecked) {
if (_selection != null && which < _selection.length) {
_selection[which] = isChecked;
_proxyAdapter.clear();
_proxyAdapter.add(buildSelectedItemString());
setSelection(0);
}
else {
throw new IllegalArgumentException("Argument 'which' is out of bounds.");
}
}
@Override
public boolean performClick() {
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setMultiChoiceItems(_items, _selection, this);
builder.setPositiveButton("Submit", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
builder.show();
return true;
}
@Override
public void setAdapter(SpinnerAdapter adapter) {
throw new RuntimeException("setAdapter is not supported by MultiSelectSpinner.");
}
public void setItems(String[] items) {
_items = items;
_selection = new boolean[_items.length];
Arrays.fill(_selection, false); // true defaults to checked, false defaults to unchecked
_proxyAdapter.clear();
_proxyAdapter.add(buildSelectedItemString());
}
public void setItemsChecked(String[] items) {
_items = items;
_selection = new boolean[_items.length];
Arrays.fill(_selection, true); // true defaults to checked, false defaults to unchecked
_proxyAdapter.clear();
_proxyAdapter.add(buildSelectedItemString());
}
public void setItemsSaved(String[] items, String saved) {
_items = items;
_selection = new boolean[_items.length];
StringBuilder sb = new StringBuilder();
boolean foundOne = false;
for (int i = 0; i < _items.length; ++i) {
_selection[i] = saved.toLowerCase().contains(_items[i].toLowerCase());
if (_selection[i]) {
if (foundOne) {
sb.append(", ");
}
foundOne = true;
sb.append(_items[i]);
}
}
_proxyAdapter.clear();
_proxyAdapter.add(buildSelectedItemString());
}
public void setItems(List<String> items) {
_items = items.toArray(new String[items.size()]);
_selection = new boolean[_items.length];
Arrays.fill(_selection, false); // true defaults to checked, false defaults to unchecked
_proxyAdapter.clear();
_proxyAdapter.add(buildSelectedItemString());
}
public void setItemsChecked(List<String> items) {
_items = items.toArray(new String[items.size()]);
_selection = new boolean[_items.length];
Arrays.fill(_selection, true); // true defaults to checked, false defaults to unchecked
_proxyAdapter.clear();
_proxyAdapter.add(buildSelectedItemString());
}
public void setSelection(String[] selection) {
for (String sel : selection) {
for (int j = 0; j < _items.length; ++j) {
if (_items[j].equals(sel)) {
_selection[j] = true;
}
}
}
}
public void setSelection(List<String> selection) {
for (String sel : selection) {
for (int j = 0; j < _items.length; ++j) {
if (_items[j].equals(sel)) {
_selection[j] = true;
}
}
}
}
public void setSelection(int[] selectedIndicies) {
for (int index : selectedIndicies) {
if (index >= 0 && index < _selection.length) {
_selection[index] = true;
}
else {
throw new IllegalArgumentException("Index " + index + " is out of bounds.");
}
}
}
public List<String> getSelectedStrings() {
List<String> selection = new LinkedList<>();
for (int i = 0; i < _items.length; ++i) {
if (_selection[i]) {
selection.add(_items[i]);
}
}
return selection;
}
public List<Integer> getSelectedIndicies() {
List<Integer> selection = new LinkedList<>();
for (int i = 0; i < _items.length; ++i) {
if (_selection[i]) {
selection.add(i);
}
}
return selection;
}
private String buildSelectedItemString() {
StringBuilder sb = new StringBuilder();
boolean foundOne = false;
for (int i = 0; i < _items.length; ++i) {
if (_selection[i]) {
if (foundOne) {
sb.append(", ");
}
foundOne = true;
sb.append(_items[i]);
}
}
return sb.toString();
}
}
and this is the Activity:
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import com.clumsygiant.ultimateimprov.MultiSelectSpinner;
import com.clumsygiant.ultimateimprov.R;
public class GameMainActivity extends Activity {
Intent mIntent = new Intent();
Context mContext = GameMainActivity.this;
String mToastText = "";
private String mCheckBoxGameCatString;
private String mCheckBoxGameSubCatString;
private String mShowRandomString = "false";
public static boolean mShowRandomStringBoolean;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game_main);
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
final SharedPreferences.Editor edit = prefs.edit();
mCheckBoxGameCatString = prefs.getString(getString(R.string.game_cat), "");
mCheckBoxGameSubCatString = prefs.getString(getString(R.string.game_sub_cat), "");
final String[] stringsGameCat = getResources().getStringArray(R.array.game_cat_array);
final MultiSelectSpinner multiSpinnerGameCat = (MultiSelectSpinner) findViewById(R.id.multiSpinnerGameCat);
if (mCheckBoxGameCatString.replace("'","").replace(" ","") == "") {
multiSpinnerGameCat.setItemsChecked(stringsGameCat);
} else {
multiSpinnerGameCat.setItemsSaved(stringsGameCat,mCheckBoxGameCatString);
}
final String[] stringsGameSubCat = getResources().getStringArray(R.array.game_sub_cat_array);
final MultiSelectSpinner multiSpinnerGameSubCat = (MultiSelectSpinner) findViewById(R.id.multiSpinnerGameSubCat);
if (mCheckBoxGameSubCatString.replace("'","") == "") {
multiSpinnerGameSubCat.setItemsChecked(stringsGameSubCat);
} else {
multiSpinnerGameSubCat.setItemsSaved(stringsGameSubCat,mCheckBoxGameSubCatString);
}
Button buttonGameCatSelectAll = (Button) findViewById(R.id.buttonGameCatSelectAll);
buttonGameCatSelectAll.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
multiSpinnerGameCat.setItemsChecked(stringsGameCat);
}
});
Button buttonGameCatSelectNone = (Button) findViewById(R.id.buttonGameCatSelectNone);
buttonGameCatSelectNone.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
multiSpinnerGameCat.setItems(stringsGameCat);
}
});
Button buttonGameSubCatSelectAll = (Button) findViewById(R.id.buttonGameSubCatSelectAll);
buttonGameSubCatSelectAll.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
multiSpinnerGameSubCat.setItemsChecked(stringsGameSubCat);
}
});
Button buttonGameSubCatSelectNone = (Button) findViewById(R.id.buttonGameSubCatSelectNone);
buttonGameSubCatSelectNone.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
multiSpinnerGameSubCat.setItems(stringsGameSubCat);
}
});
Button buttonGameList = (Button) findViewById(R.id.listGameButton);
Button buttonGameRandom = (Button) findViewById(R.id.randomGameButton);
buttonGameList.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (multiSpinnerGameCat.getSelectedStrings().toString() == "[]" || multiSpinnerGameSubCat.getSelectedStrings().toString() == "[]") {
missingMultiSpinnerToast();
}
else {
mCheckBoxGameCatString = "'" + multiSpinnerGameCat.getSelectedStrings().toString().replace("[", "").replace("]", "").replace(", ", "','") + "'";
mCheckBoxGameSubCatString = "'" + multiSpinnerGameSubCat.getSelectedStrings().toString().replace("[", "").replace("]", "").replace(", ", "','") + "'";
mShowRandomString = "false";
mShowRandomStringBoolean = false;
edit.putString(getString(R.string.game_cat), mCheckBoxGameCatString).apply();
edit.putString(getString(R.string.game_sub_cat), mCheckBoxGameSubCatString).apply();
edit.putString(getString(R.string.show_random_boolean), mShowRandomString).apply();
mIntent = new Intent(mContext, GameListActivity.class);
startActivity(mIntent);
}
}
});
buttonGameRandom.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (multiSpinnerGameCat.getSelectedStrings().toString() == "[]" || multiSpinnerGameSubCat.getSelectedStrings().toString() == "[]") {
missingMultiSpinnerToast();
}
else {
mCheckBoxGameCatString = "'" + multiSpinnerGameCat.getSelectedStrings().toString().replace("[", "").replace("]", "").replace(", ", "','") + "'";
mCheckBoxGameSubCatString = "'" + multiSpinnerGameSubCat.getSelectedStrings().toString().replace("[", "").replace("]", "").replace(", ", "','") + "'";
mShowRandomString = "true";
mShowRandomStringBoolean = true;
edit.putString(getString(R.string.game_cat), mCheckBoxGameCatString).apply();
edit.putString(getString(R.string.game_sub_cat), mCheckBoxGameSubCatString).apply();
edit.putString(getString(R.string.show_random_boolean), mShowRandomString).apply();
mIntent = new Intent(mContext, GameListActivity.class);
startActivity(mIntent);
}
}
});
}
private void missingMultiSpinnerToast() {
mToastText = getString(R.string.missing_game_filters);
Toast.makeText(mContext, mToastText, Toast.LENGTH_LONG).show();
}
}
On the detail activity, I use a SQLite database and custom SQL. I inject the values from these multi-select drop down lists into a csv format. It took a bit to get it all worked out, but it runs well now.