How do I create spinner which allows to choose multiple items, i.e spinner with check boxes?
I have written custom implementation of MultiSpinner. It's looking similar to normal spinner, but it has checkboxes instead of radiobuttons. Selected values are displayed on the spinner divided by comma. All values are checked by default. Try it:
package cz.destil.settleup.gui;
public class MultiSpinner extends Spinner implements
OnMultiChoiceClickListener, OnCancelListener {
private List<String> items;
private boolean[] selected;
private String defaultText;
private MultiSpinnerListener listener;
public MultiSpinner(Context context) {
super(context);
}
public MultiSpinner(Context arg0, AttributeSet arg1) {
super(arg0, arg1);
}
public MultiSpinner(Context arg0, AttributeSet arg1, int arg2) {
super(arg0, arg1, arg2);
}
#Override
public void onClick(DialogInterface dialog, int which, boolean isChecked) {
if (isChecked)
selected[which] = true;
else
selected[which] = false;
}
#Override
public void onCancel(DialogInterface dialog) {
// refresh text on spinner
StringBuffer spinnerBuffer = new StringBuffer();
boolean someSelected = false;
for (int i = 0; i < items.size(); i++) {
if (selected[i] == true) {
spinnerBuffer.append(items.get(i));
spinnerBuffer.append(", ");
someSelected = true;
}
}
String spinnerText;
if (someSelected) {
spinnerText = spinnerBuffer.toString();
if (spinnerText.length() > 2)
spinnerText = spinnerText.substring(0, spinnerText.length() - 2);
} else {
spinnerText = defaultText;
}
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getContext(),
android.R.layout.simple_spinner_item,
new String[] { spinnerText });
setAdapter(adapter);
listener.onItemsSelected(selected);
}
#Override
public boolean performClick() {
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setMultiChoiceItems(
items.toArray(new CharSequence[items.size()]), selected, this);
builder.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
builder.setOnCancelListener(this);
builder.show();
return true;
}
public void setItems(List<String> items, String allText,
MultiSpinnerListener listener) {
this.items = items;
this.defaultText = allText;
this.listener = listener;
// all selected by default
selected = new boolean[items.size()];
for (int i = 0; i < selected.length; i++)
selected[i] = true;
// all text on the spinner
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getContext(),
android.R.layout.simple_spinner_item, new String[] { allText });
setAdapter(adapter);
}
public interface MultiSpinnerListener {
public void onItemsSelected(boolean[] selected);
}
}
You use it in XML like this:
<cz.destil.settleup.gui.MultiSpinner android:id="#+id/multi_spinner" />
And you pass data to it in Java like this:
MultiSpinner multiSpinner = (MultiSpinner) findViewById(R.id.multi_spinner);
multiSpinner.setItems(items, getString(R.string.for_all), this);
Also you need to implement the listener,which will return the same length array , with true or false to show selected to unselected..
public void onItemsSelected(boolean[] selected);
I would just like to show an alternative version of #Destil's MultiSpinner (thank you for your inspiring code) which allows to use "android:entries" in xml, just like a spinner.
It doesn't initially show a default text, like "choose one", but you can easily obtain it by setting an additional ArrayAdapter in the constructor.
MultiSpinner.java
package com.example.helloworld;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnMultiChoiceClickListener;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
/**
* Inspired by: http://stackoverflow.com/a/6022474/1521064
*/
public class MultiSpinner extends Spinner {
private CharSequence[] entries;
private boolean[] selected;
private MultiSpinnerListener listener;
public MultiSpinner(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MultiSpinner);
entries = a.getTextArray(R.styleable.MultiSpinner_android_entries);
if (entries != null) {
selected = new boolean[entries.length]; // false-filled by default
}
a.recycle();
}
private OnMultiChoiceClickListener mOnMultiChoiceClickListener = new OnMultiChoiceClickListener() {
#Override
public void onClick(DialogInterface dialog, int which, boolean isChecked) {
selected[which] = isChecked;
}
};
private DialogInterface.OnClickListener mOnClickListener = new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// build new spinner text & delimiter management
StringBuffer spinnerBuffer = new StringBuffer();
for (int i = 0; i < entries.length; i++) {
if (selected[i]) {
spinnerBuffer.append(entries[i]);
spinnerBuffer.append(", ");
}
}
// Remove trailing comma
if (spinnerBuffer.length() > 2) {
spinnerBuffer.setLength(spinnerBuffer.length() - 2);
}
// display new text
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getContext(),
android.R.layout.simple_spinner_item,
new String[] { spinnerBuffer.toString() });
setAdapter(adapter);
if (listener != null) {
listener.onItemsSelected(selected);
}
// hide dialog
dialog.dismiss();
}
};
#Override
public boolean performClick() {
new AlertDialog.Builder(getContext())
.setMultiChoiceItems(entries, selected, mOnMultiChoiceClickListener)
.setPositiveButton(android.R.string.ok, mOnClickListener)
.show();
return true;
}
public void setMultiSpinnerListener(MultiSpinnerListener listener) {
this.listener = listener;
}
public interface MultiSpinnerListener {
public void onItemsSelected(boolean[] selected);
}
}
attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MultiSpinner">
<attr name="android:entries" />
</declare-styleable>
</resources>
layout_main_activity.xml
<com.example.helloworld.MultiSpinner
android:id="#+id/multispinner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:entries="#array/multispinner_entries" />
As far as I know Spinner doesn't have a multiple choice mode. Instead you can create an ImageButton and set a drawable down arrow in the right side and on the click event you can open a Dialog having items with the multiple checkboxes.
Thanks for the post! Great solution. I made a small change to the class (method setItems) to allow users to set already selected items instead of selecting all items to true by default.
public void setItems(
List<String> items,
List<String> itemValues,
String selectedList,
String allText,
MultiSpinnerListener listener) {
this.items = items;
this.defaultText = allText;
this.listener = listener;
String spinnerText = allText;
// Set false by default
selected = new boolean[itemValues.size()];
for (int j = 0; j < itemValues.size(); j++)
selected[j] = false;
if (selectedList != null) {
spinnerText = "";
// Extract selected items
String[] selectedItems = selectedList.trim().split(",");
// Set selected items to true
for (int i = 0; i < selectedItems.length; i++)
for (int j = 0; j < itemValues.size(); j++)
if (selectedItems[i].trim().equals(itemValues.get(j))) {
selected[j] = true;
spinnerText += (spinnerText.equals("")?"":", ") + items.get(j);
break;
}
}
// Text for the spinner
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getContext(),
android.R.layout.simple_spinner_item, new String[] { spinnerText });
setAdapter(adapter);
}
You can check a simple library MultiSelectSpinner
You can simply do the following steps:
multiSelectSpinnerWithSearch.setItems(listArray1, new MultiSpinnerListener() {
#Override
public void onItemsSelected(List<KeyPairBoolData> items) {
for (int i = 0; i < items.size(); i++) {
if (items.get(i).isSelected()) {
Log.i(TAG, i + " : " + items.get(i).getName() + " : " + items.get(i).isSelected());
}
}
}
});
The listArray1 will be your array.
Check the full example here in How-To
Related
I need to let the user to choose city in the preferences, there are many cities so I used this project to search in the list, its working great, but I need to implement it inside preferences xml, and not in a regular layout.
here is what I had before, [Main Activity class, works fine in regular layout]:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/**
* Getting array of String to Bind in Spinner
*/
final List<String> list = Arrays.asList(getResources().getStringArray(R.array.sports_array));
/**
* Search MultiSelection Spinner (With Search/Filter Functionality)
*
* Using MultiSpinnerSearch class
*/
MultiSpinnerSearch searchSpinner = (MultiSpinnerSearch) findViewById(R.id.searchMultiSpinner);
final List<KeyPairBoolData> listArray = new ArrayList<KeyPairBoolData>();
for(int i=0; i<list.size(); i++) {
KeyPairBoolData h = new KeyPairBoolData();
h.setId(i+1);
h.setName(list.get(i));
h.setSelected(false);
listArray.add(h);
}
/***
* -1 is no by default selection
* 0 to length will select corresponding values
*/
searchSpinner.setItems(listArray, "Multi Selection With Filter", -1, new MultiSpinnerSearchListener() {
#Override
public void onItemsSelected(List<KeyPairBoolData> items) {
for(int i=0; i<items.size(); i++) {
if(items.get(i).isSelected()) {
Log.i("TAG", i + " : " + items.get(i).getName() + " : " + items.get(i).isSelected());
}
}
}
});
}
in the layout I had:
<com.androidbuts.multispinnerfilter.MultiSpinnerSearch
android:id="#+id/searchMultiSpinner"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:layout_marginTop="20dp" >
</com.androidbuts.multispinnerfilter.MultiSpinnerSearch>
and the original class was:
public class MultiSpinnerSearch extends Spinner implements OnCancelListener {
private List<KeyPairBoolData> items;
//private boolean[] selected;
private String defaultText;
private MultiSpinnerSearchListener listener;
MyAdapter adapter;
public MultiSpinnerSearch(Context context) {
super(context);
}
public MultiSpinnerSearch(Context arg0, AttributeSet arg1) {
super(arg0, arg1);
}
public MultiSpinnerSearch(Context arg0, AttributeSet arg1, int arg2) {
super(arg0, arg1, arg2);
}
#Override
public void onCancel(DialogInterface dialog) {
// refresh text on spinner
StringBuffer spinnerBuffer = new StringBuffer();
for (int i = 0; i < items.size(); i++) {
if (items.get(i).isSelected() == true) {
spinnerBuffer.append(items.get(i).getName());
spinnerBuffer.append(", ");
}
}
String spinnerText = "";
spinnerText = spinnerBuffer.toString();
if (spinnerText.length() > 2)
spinnerText = spinnerText.substring(0, spinnerText.length() - 2);
else
spinnerText = defaultText;
ArrayAdapter<String> adapterSpinner = new ArrayAdapter<String>(getContext(),
R.layout.textview_for_spinner,
new String[] { spinnerText });
setAdapter(adapterSpinner);
if(adapter != null)
adapter.notifyDataSetChanged();
listener.onItemsSelected(items);
}
#Override
public boolean performClick() {
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle(defaultText);
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService( Context.LAYOUT_INFLATER_SERVICE );
View view = inflater.inflate(R.layout.alert_dialog_listview_search, null);
builder.setView(view);
final ListView listView = (ListView) view.findViewById(R.id.alertSearchListView);
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
listView.setFastScrollEnabled(false);
adapter = new MyAdapter(getContext(), items);
listView.setAdapter(adapter);
EditText editText = (EditText) view.findViewById(R.id.alertSearchEditText);
editText.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
adapter.getFilter().filter(s.toString());
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void afterTextChanged(Editable s) {
}
});
//builder.setMultiChoiceItems(items.toArray(new CharSequence[items.size()]), selected, this);
builder.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// items = (ArrayList<KeyPairBoolData>) adapter.arrayList;
Log.i("TAG", " ITEMS : " + items.size() );
dialog.cancel();
}
});
builder.setOnCancelListener(this);
builder.show();
return true;
}
public void setItems(List<KeyPairBoolData> items, String allText, int position,
MultiSpinnerSearchListener listener) {
this.items = items;
this.defaultText = allText;
this.listener = listener;
ArrayAdapter<String> adapterSpinner = new ArrayAdapter<String>(getContext(),
R.layout.textview_for_spinner,
new String[] { defaultText });
setAdapter(adapterSpinner);
if(position != -1)
{
items.get(position).setSelected(true);
//listener.onItemsSelected(items);
onCancel(null);
}
}
public interface MultiSpinnerSearchListener {
public void onItemsSelected(List<KeyPairBoolData> items);
}
// // Adapter Class
public class MyAdapter extends BaseAdapter implements Filterable {
List<KeyPairBoolData> arrayList;
List<KeyPairBoolData> mOriginalValues; // Original Values
LayoutInflater inflater;
public MyAdapter(Context context, List<KeyPairBoolData> arrayList) {
this.arrayList = arrayList;
inflater = LayoutInflater.from(context);
}
#Override
public int getCount() {
return arrayList.size();
}
#Override
public Object getItem(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
private class ViewHolder {
TextView textView;
CheckBox checkBox;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) {
holder = new ViewHolder();
convertView = inflater.inflate(R.layout.alert_dialog_listview_search_subview, null);
holder.textView = (TextView) convertView.findViewById(R.id.alertTextView);
holder.checkBox = (CheckBox) convertView.findViewById(R.id.alertCheckbox);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
final KeyPairBoolData data = arrayList.get(position);
holder.textView.setText(data.getName());
holder.checkBox.setChecked(data.isSelected());
convertView.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
ViewHolder temp = (ViewHolder) v.getTag();
temp.checkBox.setChecked(!temp.checkBox.isChecked());
int len = arrayList.size();
for (int i = 0; i < len; i++)
{
if (i == position)
{
data.setSelected(!data.isSelected());
Log.i("TAG", "On Click Selected : " + data.getName() + " : " + data.isSelected());
break;
}
}
}
});
holder.checkBox.setTag(holder);
return convertView;
}
#SuppressLint("DefaultLocale")
#Override
public Filter getFilter() {
Filter filter = new Filter() {
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint,FilterResults results) {
arrayList = (List<KeyPairBoolData>) results.values; // has the filtered values
notifyDataSetChanged(); // notifies the data with new filtered values
}
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults(); // Holds the results of a filtering operation in values
List<KeyPairBoolData> FilteredArrList = new ArrayList<KeyPairBoolData>();
if (mOriginalValues == null) {
mOriginalValues = new ArrayList<KeyPairBoolData>(arrayList); // saves the original data in mOriginalValues
}
/********
*
* If constraint(CharSequence that is received) is null returns the mOriginalValues(Original) values
* else does the Filtering and returns FilteredArrList(Filtered)
*
********/
if (constraint == null || constraint.length() == 0) {
// set the Original result to return
results.count = mOriginalValues.size();
results.values = mOriginalValues;
} else {
constraint = constraint.toString().toLowerCase();
for (int i = 0; i < mOriginalValues.size(); i++) {
Log.i("TAG", "Filter : " + mOriginalValues.get(i).getName() + " -> " + mOriginalValues.get(i).isSelected());
String data = mOriginalValues.get(i).getName();
if (data.toLowerCase().contains(constraint.toString())) {
FilteredArrList.add(mOriginalValues.get(i));
}
}
// set the Filtered result to return
results.count = FilteredArrList.size();
results.values = FilteredArrList;
}
return results;
}
};
return filter;
}
}
}
And here is what I'm trying to do, PreferencesSpinner Class (almost same as above):
public class PreferencesSpinner extends DialogPreference implements OnCancelListener {
private List<KeyPairBoolData> items;
public Spinner spinner;
//private boolean[] selected;
private String defaultText;
private PreferencesSpinnerListener listener;
MyAdapter adapter;
public PreferencesSpinner(Context context) {
super(context);
}
public PreferencesSpinner(Context arg0, AttributeSet arg1) {
super(arg0, arg1);
}
public PreferencesSpinner(Context arg0, AttributeSet arg1, int arg2) {
super(arg0, arg1, arg2);
}
#Override
public void onCancel(DialogInterface dialog) {
// refresh text on spinner
StringBuffer spinnerBuffer = new StringBuffer();
for (int i = 0; i < items.size(); i++) {
if (items.get(i).isSelected() == true) {
spinnerBuffer.append(items.get(i).getName());
spinnerBuffer.append(", ");
}
}
String spinnerText = "";
spinnerText = spinnerBuffer.toString();
if (spinnerText.length() > 2)
spinnerText = spinnerText.substring(0, spinnerText.length() - 2);
else
spinnerText = defaultText;
ArrayAdapter<String> adapterSpinner = new ArrayAdapter<String>(getContext(),
R.layout.textview_for_spinner,
new String[] { spinnerText });
spinner.setAdapter(adapterSpinner);
if(adapter != null)
adapter.notifyDataSetChanged();
listener.onItemsSelected(items);
}
public boolean performClick() {
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle(defaultText);
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService( Context.LAYOUT_INFLATER_SERVICE );
View view = inflater.inflate(R.layout.alert_dialog_listview_search, null);
builder.setView(view);
final ListView listView = (ListView) view.findViewById(R.id.alertSearchListView);
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
listView.setFastScrollEnabled(false);
adapter = new MyAdapter(getContext(), items);
listView.setAdapter(adapter);
EditText editText = (EditText) view.findViewById(R.id.alertSearchEditText);
editText.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
adapter.getFilter().filter(s.toString());
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void afterTextChanged(Editable s) {
}
});
//builder.setMultiChoiceItems(items.toArray(new CharSequence[items.size()]), selected, this);
builder.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// items = (ArrayList<KeyPairBoolData>) adapter.arrayList;
Log.i("TAG", " ITEMS : " + items.size() );
dialog.cancel();
}
});
builder.setOnCancelListener(this);
builder.show();
return true;
}
public void setItems(List<KeyPairBoolData> items, String allText, int position,
PreferencesSpinnerListener listener) {
this.items = items;
this.defaultText = allText;
this.listener = listener;
ArrayAdapter<String> adapterSpinner = new ArrayAdapter<String>(getContext(),
R.layout.textview_for_spinner,
new String[] { defaultText });
spinner.setAdapter(adapterSpinner);
if(position != -1)
{
items.get(position).setSelected(true);
//listener.onItemsSelected(items);
onCancel(null);
}
}
public interface PreferencesSpinnerListener {
public void onItemsSelected(List<KeyPairBoolData> items);
}
// // Adapter Class
public class MyAdapter extends BaseAdapter implements Filterable {
List<KeyPairBoolData> arrayList;
List<KeyPairBoolData> mOriginalValues; // Original Values
LayoutInflater inflater;
public MyAdapter(Context context, List<KeyPairBoolData> arrayList) {
this.arrayList = arrayList;
inflater = LayoutInflater.from(context);
}
#Override
public int getCount() {
return arrayList.size();
}
#Override
public Object getItem(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
private class ViewHolder {
TextView textView;
CheckBox checkBox;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) {
holder = new ViewHolder();
convertView = inflater.inflate(R.layout.alert_dialog_listview_search_subview, null);
holder.textView = (TextView) convertView.findViewById(R.id.alertTextView);
holder.checkBox = (CheckBox) convertView.findViewById(R.id.alertCheckbox);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
final KeyPairBoolData data = arrayList.get(position);
holder.textView.setText(data.getName());
holder.checkBox.setChecked(data.isSelected());
convertView.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
ViewHolder temp = (ViewHolder) v.getTag();
temp.checkBox.setChecked(!temp.checkBox.isChecked());
int len = arrayList.size();
for (int i = 0; i < len; i++)
{
if (i == position)
{
data.setSelected(!data.isSelected());
Log.i("TAG", "On Click Selected : " + data.getName() + " : " + data.isSelected());
break;
}
}
}
});
holder.checkBox.setTag(holder);
return convertView;
}
#SuppressLint("DefaultLocale")
#Override
public Filter getFilter() {
Filter filter = new Filter() {
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint,FilterResults results) {
arrayList = (List<KeyPairBoolData>) results.values; // has the filtered values
notifyDataSetChanged(); // notifies the data with new filtered values
}
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults(); // Holds the results of a filtering operation in values
List<KeyPairBoolData> FilteredArrList = new ArrayList<KeyPairBoolData>();
if (mOriginalValues == null) {
mOriginalValues = new ArrayList<KeyPairBoolData>(arrayList); // saves the original data in mOriginalValues
}
/********
*
* If constraint(CharSequence that is received) is null returns the mOriginalValues(Original) values
* else does the Filtering and returns FilteredArrList(Filtered)
*
********/
if (constraint == null || constraint.length() == 0) {
// set the Original result to return
results.count = mOriginalValues.size();
results.values = mOriginalValues;
} else {
constraint = constraint.toString().toLowerCase();
for (int i = 0; i < mOriginalValues.size(); i++) {
Log.i("TAG", "Filter : " + mOriginalValues.get(i).getName() + " -> " + mOriginalValues.get(i).isSelected());
String data = mOriginalValues.get(i).getName();
if (data.toLowerCase().contains(constraint.toString())) {
FilteredArrList.add(mOriginalValues.get(i));
}
}
// set the Filtered result to return
results.count = FilteredArrList.size();
results.values = FilteredArrList;
}
return results;
}
};
return filter;
}
}
}
with Preferences.xml:
<com.androidbuts.multispinnerfilter.PreferencesSpinner
android:key="spinner"
android:title="spinner Title"
android:summary="Summary"/>
and of course, Preferences class:
public class Preferences extends PreferenceActivity {
public PreferencesSpinner searchSpinner;
#SuppressWarnings("deprecation")
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
final List<String> list = Arrays.asList(getResources().getStringArray(R.array.sports_array));
final List<KeyPairBoolData> listArray = new ArrayList<KeyPairBoolData>();
for(int i=0; i<list.size(); i++) {
KeyPairBoolData h = new KeyPairBoolData();
h.setId(i+1);
h.setName(list.get(i));
h.setSelected(false);
listArray.add(h);
}
searchSpinner = (PreferencesSpinner) findPreference("spinner");
searchSpinner.setItems(listArray, "all text", -1, new PreferencesSpinner.PreferencesSpinnerListener() {
#Override
public void onItemsSelected(List<KeyPairBoolData> items) {
}
});
}
anyone can help me with the migration to preferences Activity?
Thanks!
Whoever need it, Here is the answer:
#Override
protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService( Context.LAYOUT_INFLATER_SERVICE );
View view = inflater.inflate(R.layout.alert_dialog_listview_search, null);
builder.setView(view);
final ListView listView = (ListView) view.findViewById(R.id.alertSearchListView);
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
listView.setFastScrollEnabled(false);
final List<String> list = Arrays.asList(view.getResources().getStringArray(R.array.sports_array));
final List<KeyPairBoolData> listArray = new ArrayList<KeyPairBoolData>();
for(int i=0; i<list.size(); i++) {
KeyPairBoolData h = new KeyPairBoolData();
h.setId(i+1);
h.setName(list.get(i));
h.setSelected(false);
listArray.add(h);
}
setItems(listArray, "all text", -1, new PreferencesSpinnerListener() {
#Override
public void onItemsSelected(List<KeyPairBoolData> items) {
}
});
adapter = new MyAdapter(getContext(), items);
listView.setAdapter(adapter);
EditText editText = (EditText) view.findViewById(R.id.alertSearchEditText);
editText.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
adapter.getFilter().filter(s.toString());
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void afterTextChanged(Editable s) {
}
});
//builder.setMultiChoiceItems(items.toArray(new CharSequence[items.size()]), selected, this);
builder.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// items = (ArrayList<KeyPairBoolData>) adapter.arrayList;
Log.i("TAG", " ITEMS : " + items.size() );
dialog.cancel();
}
});
builder.setOnCancelListener(this);
}
Hope that's help..
I recently posted my Question for MultiSpinner values to choose Multiple values from Spinner dialog. I've done successfully with following class.
MultiSpinnerSearch.java
package com.example.multiplechoicelistwithfilter;
import java.util.List;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.util.SparseBooleanArray;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Spinner;
public class MultiSpinnerSearch extends Spinner implements OnCancelListener {
private List<Hello> items;
//private boolean[] selected;
private String defaultText;
private MultiSpinnerListener listener;
public MultiSpinnerSearch(Context context) {
super(context);
}
public MultiSpinnerSearch(Context arg0, AttributeSet arg1) {
super(arg0, arg1);
}
public MultiSpinnerSearch(Context arg0, AttributeSet arg1, int arg2) {
super(arg0, arg1, arg2);
}
#Override
public void onCancel(DialogInterface dialog) {
// refresh text on spinner
StringBuffer spinnerBuffer = new StringBuffer();
for (int i = 0; i < items.size(); i++) {
if (items.get(i).isSelected() == true) {
spinnerBuffer.append(items.get(i).getName());
spinnerBuffer.append(", ");
}
}
String spinnerText = "";
spinnerText = spinnerBuffer.toString();
if (spinnerText.length() > 2)
spinnerText = spinnerText.substring(0, spinnerText.length() - 2);
else
spinnerText = defaultText;
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getContext(),
android.R.layout.simple_dropdown_item_1line,
new String[] { spinnerText });
setAdapter(adapter);
listener.onItemsSelected(items);
}
#Override
public boolean performClick() {
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle(defaultText);
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService( Context.LAYOUT_INFLATER_SERVICE );
View view = inflater.inflate(R.layout.alert_dialog_listview_search, null);
builder.setView(view);
final ListView listView = (ListView) view.findViewById(R.id.alertSearchListView);
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
final MyAdapter adapter = new MyAdapter(getContext(), items);
listView.setAdapter(adapter);
EditText editText = (EditText) view.findViewById(R.id.alertSearchEditText);
editText.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
adapter.getFilter().filter(s.toString());
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void afterTextChanged(Editable s) {
}
});
//builder.setMultiChoiceItems(items.toArray(new CharSequence[items.size()]), selected, this);
builder.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
SparseBooleanArray sp = listView.getCheckedItemPositions();
for(int i=0;i<items.size();i++) {
items.get(i).setSelected(sp.get(i));
}
dialog.cancel();
}
});
builder.setOnCancelListener(this);
builder.show();
return true;
}
public void setItems(List<Hello> items, String allText, int position,
MultiSpinnerListener listener) {
this.items = items;
this.defaultText = allText;
this.listener = listener;
// all selected by default
//selected = new boolean[items.size()];
//for (int i = 0; i < selected.length; i++)
// selected[i] = false;
if(position != -1)
{
items.get(position).setSelected(true);
listener.onItemsSelected(items);
onCancel(null);
}
}
public interface MultiSpinnerListener {
public void onItemsSelected(List<Hello> items);
}
}
MyAdapter class:
package com.example.multiplechoicelistwithfilter;
import java.util.ArrayList;
import java.util.List;
import android.annotation.SuppressLint;
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckedTextView;
import android.widget.Filter;
import android.widget.Filterable;
public class MyAdapter extends BaseAdapter implements Filterable {
List<Hello> arrayList;
List<Hello> mOriginalValues; // Original Values
LayoutInflater inflater;
public MyAdapter(Context context, List<Hello> arrayList) {
this.arrayList = arrayList;
inflater = LayoutInflater.from(context);
}
#Override
public int getCount() {
return arrayList.size();
}
#Override
public Object getItem(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
private class ViewHolder {
CheckedTextView textView;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) {
holder = new ViewHolder();
convertView = inflater.inflate(android.R.layout.select_dialog_multichoice, null);
holder.textView = (CheckedTextView) convertView;
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.textView.setText(arrayList.get(position).getName());
holder.textView.setChecked(arrayList.get(position).isSelected());
return convertView;
}
#SuppressLint("DefaultLocale")
#Override
public Filter getFilter() {
Filter filter = new Filter() {
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint,FilterResults results) {
arrayList = (List<Hello>) results.values; // has the filtered values
notifyDataSetChanged(); // notifies the data with new filtered values
}
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults(); // Holds the results of a filtering operation in values
List<Hello> FilteredArrList = new ArrayList<Hello>();
if (mOriginalValues == null) {
mOriginalValues = new ArrayList<Hello>(arrayList); // saves the original data in mOriginalValues
}
/********
*
* If constraint(CharSequence that is received) is null returns the mOriginalValues(Original) values
* else does the Filtering and returns FilteredArrList(Filtered)
*
********/
if (constraint == null || constraint.length() == 0) {
// set the Original result to return
results.count = mOriginalValues.size();
results.values = mOriginalValues;
} else {
constraint = constraint.toString().toLowerCase();
for (int i = 0; i < mOriginalValues.size(); i++) {
Log.i("TAG", "" + mOriginalValues.get(i).getName() + " -> " + mOriginalValues.get(i).isSelected());
String data = mOriginalValues.get(i).getName();
if (data.toLowerCase().contains(constraint.toString())) {
FilteredArrList.add(mOriginalValues.get(i));
}
}
// set the Filtered result to return
results.count = FilteredArrList.size();
results.values = FilteredArrList;
}
return results;
}
};
return filter;
}
}
I am getting output successfully as below, but in first image suppose
i am select first two image and then filtering word 'ball' it gives me
filtered result with selected checkbox as before.
You can see that first two items not selected before but it shows
selected while filtering.
I am stuck with this silly problem since last couple of hours. Help me.
Your help would be appreciated. Thanks.
I have created my own lib and uploaded on Git:
May It will help you all:
MultiSelectSpinner is allows to Select Multiple Items from Spinner and SEARCH/ FILTER Item from Spinner Items.
public class MultiSpinnerSearch extends Spinner implements OnCancelListener {
private List<KeyPairBoolData> items;
//private boolean[] selected;
private String defaultText;
private MultiSpinnerSearchListener listener;
MyAdapter adapter;
public MultiSpinnerSearch(Context context) {
super(context);
}
public MultiSpinnerSearch(Context arg0, AttributeSet arg1) {
super(arg0, arg1);
}
public MultiSpinnerSearch(Context arg0, AttributeSet arg1, int arg2) {
super(arg0, arg1, arg2);
}
#Override
public void onCancel(DialogInterface dialog) {
// refresh text on spinner
StringBuffer spinnerBuffer = new StringBuffer();
for (int i = 0; i < items.size(); i++) {
if (items.get(i).isSelected() == true) {
spinnerBuffer.append(items.get(i).getName());
spinnerBuffer.append(", ");
}
}
String spinnerText = "";
spinnerText = spinnerBuffer.toString();
if (spinnerText.length() > 2)
spinnerText = spinnerText.substring(0, spinnerText.length() - 2);
else
spinnerText = defaultText;
ArrayAdapter<String> adapterSpinner = new ArrayAdapter<String>(getContext(),
R.layout.textview_for_spinner,
new String[] { spinnerText });
setAdapter(adapterSpinner);
if(adapter != null)
adapter.notifyDataSetChanged();
listener.onItemsSelected(items);
}
#Override
public boolean performClick() {
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle(defaultText);
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService( Context.LAYOUT_INFLATER_SERVICE );
View view = inflater.inflate(R.layout.alert_dialog_listview_search, null);
builder.setView(view);
final ListView listView = (ListView) view.findViewById(R.id.alertSearchListView);
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
listView.setFastScrollEnabled(false);
adapter = new MyAdapter(getContext(), items);
listView.setAdapter(adapter);
EditText editText = (EditText) view.findViewById(R.id.alertSearchEditText);
editText.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
adapter.getFilter().filter(s.toString());
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void afterTextChanged(Editable s) {
}
});
//builder.setMultiChoiceItems(items.toArray(new CharSequence[items.size()]), selected, this);
builder.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// items = (ArrayList<KeyPairBoolData>) adapter.arrayList;
Log.i("TAG", " ITEMS : " + items.size() );
dialog.cancel();
}
});
builder.setOnCancelListener(this);
builder.show();
return true;
}
public void setItems(List<KeyPairBoolData> items, String allText, int position,
MultiSpinnerSearchListener listener) {
this.items = items;
this.defaultText = allText;
this.listener = listener;
ArrayAdapter<String> adapterSpinner = new ArrayAdapter<String>(getContext(),
R.layout.textview_for_spinner,
new String[] { defaultText });
setAdapter(adapterSpinner);
if(position != -1)
{
items.get(position).setSelected(true);
//listener.onItemsSelected(items);
onCancel(null);
}
}
public interface MultiSpinnerSearchListener {
public void onItemsSelected(List<KeyPairBoolData> items);
}
// // Adapter Class
public class MyAdapter extends BaseAdapter implements Filterable {
List<KeyPairBoolData> arrayList;
List<KeyPairBoolData> mOriginalValues; // Original Values
LayoutInflater inflater;
public MyAdapter(Context context, List<KeyPairBoolData> arrayList) {
this.arrayList = arrayList;
inflater = LayoutInflater.from(context);
}
#Override
public int getCount() {
return arrayList.size();
}
#Override
public Object getItem(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
private class ViewHolder {
TextView textView;
CheckBox checkBox;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) {
holder = new ViewHolder();
convertView = inflater.inflate(R.layout.alert_dialog_listview_search_subview, null);
holder.textView = (TextView) convertView.findViewById(R.id.alertTextView);
holder.checkBox = (CheckBox) convertView.findViewById(R.id.alertCheckbox);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
final KeyPairBoolData data = arrayList.get(position);
holder.textView.setText(data.getName());
holder.checkBox.setChecked(data.isSelected());
convertView.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
ViewHolder temp = (ViewHolder) v.getTag();
temp.checkBox.setChecked(!temp.checkBox.isChecked());
int len = arrayList.size();
for (int i = 0; i < len; i++)
{
if (i == position)
{
data.setSelected(!data.isSelected());
Log.i("TAG", "On Click Selected : " + data.getName() + " : " + data.isSelected());
break;
}
}
}
});
holder.checkBox.setTag(holder);
return convertView;
}
#SuppressLint("DefaultLocale")
#Override
public Filter getFilter() {
Filter filter = new Filter() {
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint,FilterResults results) {
arrayList = (List<KeyPairBoolData>) results.values; // has the filtered values
notifyDataSetChanged(); // notifies the data with new filtered values
}
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults(); // Holds the results of a filtering operation in values
List<KeyPairBoolData> FilteredArrList = new ArrayList<KeyPairBoolData>();
if (mOriginalValues == null) {
mOriginalValues = new ArrayList<KeyPairBoolData>(arrayList); // saves the original data in mOriginalValues
}
/********
*
* If constraint(CharSequence that is received) is null returns the mOriginalValues(Original) values
* else does the Filtering and returns FilteredArrList(Filtered)
*
********/
if (constraint == null || constraint.length() == 0) {
// set the Original result to return
results.count = mOriginalValues.size();
results.values = mOriginalValues;
} else {
constraint = constraint.toString().toLowerCase();
for (int i = 0; i < mOriginalValues.size(); i++) {
Log.i("TAG", "Filter : " + mOriginalValues.get(i).getName() + " -> " + mOriginalValues.get(i).isSelected());
String data = mOriginalValues.get(i).getName();
if (data.toLowerCase().contains(constraint.toString())) {
FilteredArrList.add(mOriginalValues.get(i));
}
}
// set the Filtered result to return
results.count = FilteredArrList.size();
results.values = FilteredArrList;
}
return results;
}
};
return filter;
}
}
}
Thanks :) Keep Sharing :)
I have a custom list view, contains delete button and spinner (the spinner contain A-E characters).
And I have an issue with deleting the true row from my custom list view.
Custom list view code:
public class customListView extends BaseAdapter
{
public Activity context;
ArrayList<MyActivity.UserProperties> userPropertieses;
public String[] spinnerValues;
public LayoutInflater inflater;
public customListView(Activity context, ArrayList<MyActivity.UserProperties> userPropertieses, String[] spinnerArray)
{
super();
this.context = context;
this.userPropertieses = userPropertieses;
spinnerValues = spinnerArray;
this.inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() { return userPropertieses.size(); }
#Override
public Object getItem(int i) { return null; }
#Override
public long getItemId(int i) { return 0; }
class ViewHolder
{
Button btnRemove;
Spinner spinner;
}
#Override
public View getView(final int i, View view, ViewGroup viewGroup)
{
final ViewHolder holder;
if (view == null)
{
holder = new ViewHolder();
view = inflater.inflate(R.layout.custom_layout, null);
holder.spinner = (Spinner) view.findViewById(R.id.spinner);
holder.btnRemove = (Button) view.findViewById(R.id.bu_Remove);
// populate spinner
ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>
(view.getContext(), android.R.layout.simple_spinner_item, spinnerValues);
dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
holder.spinner.setFocusable(true);
holder.spinner.requestFocus();
holder.spinner.setAdapter(dataAdapter);
view.setTag(holder);
// remove user implementation
holder.btnRemove.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.i("custom list view debug", "i = " + i); // debug. verify i value is correct
((MyActivity) context).deleteUser(i);
}
});
}
else
holder = (ViewHolder) view.getTag();
return view;
}
}
And my main activity code looks like this:
public class MyActivity extends Activity
{
ListView listView;
ArrayList<UserProperties> userProperties = new ArrayList<UserProperties>();
customListView adapter;
SensorManager sensorManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
for (int i = 0; i<5; i++) {
userProperties.add(new UserProperties());
}
listView = (ListView) findViewById(R.id.listView);
String[] spinnerValues = new String[] {"A", "B", "C", "D", "E"};
adapter = new customListView(MyActivity.this, userProperties, spinnerValues);
listView.setAdapter(adapter);
}
public void deleteUser (int index)
{
Log.i("debug", "Removing item " + index); // the index is really true and the true node deleting from the ArrayList but somehow the latest delete from the UI
userProperties.remove(index);
adapter.notifyDataSetChanged();
}
}
When I click on the Remove button deleteUser method called with the right index. but although the right node deleting from userProperties ArrayList somehow after notiftDataSetChanged is still alive
and the latest node delete.
So, How can I delete the right node/row (from the ArrayList and UI...)
Thank you!
EDIT:
Just to be clear, i variable contain true index. The true node deleted from the ArrayList. but something append after I called notify method.
I prefer to stay with BaseAdapter and not implement ArrayAdapter. Thank you!
EDIT 2:
After more debugging I found out my question was wrong. the true row really deleted just spinner values somehow update their values. I cannot close the question because it already answered. Thanks.
((MyActivity) context).deleteUser(i);
This line will always delete the first value from the ListView
You can use CAB (contextual action bar)
See if the code helps you(it's basically a ListActivity with a custom adapter to hold the status of checked items(+ different background)):
public class CABSelection extends ListActivity {
private ArrayList<String> mItems = new ArrayList<String>();
private SelectionAdapter mAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
for (int i = 0; i < 24; i++) {
mItems.add("Name" + i);
}
// R.layout.adapters_cabselection_row is a LinearLayout(with green
// background(#99cc00)) that wraps an ImageView and a TextView
mAdapter = new SelectionAdapter(this,
R.layout.adapters_cabselection_row, R.id.the_text, mItems);
setListAdapter(mAdapter);
getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
getListView().setMultiChoiceModeListener(new MultiChoiceModeListener() {
private int nr = 0;
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.cabselection_menu, menu);
return true;
}
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
StringBuilder sb = new StringBuilder();
Set<Integer> positions = mAdapter.getCurrentCheckedPosition();
for (Integer pos : positions) {
sb.append(" " + pos + ",");
}
switch (item.getItemId()) {
case R.id.edit_entry:
Toast.makeText(CABSelection.this, "Edited entries: " + sb.toString(),
Toast.LENGTH_SHORT).show();
break;
case R.id.delete_entry:
Toast.makeText(CABSelection.this, "Deleted entries : " + sb.toString(),
Toast.LENGTH_SHORT).show();
break;
case R.id.finish_it:
nr = 0;
mAdapter.clearSelection();
Toast.makeText(CABSelection.this, "Finish the CAB!",
Toast.LENGTH_SHORT).show();
mode.finish();
}
return false;
}
#Override
public void onDestroyActionMode(ActionMode mode) {
nr = 0;
mAdapter.clearSelection();
}
#Override
public void onItemCheckedStateChanged(ActionMode mode,
int position, long id, boolean checked) {
if (checked) {
nr++;
mAdapter.setNewSelection(position, checked);
} else {
nr--;
mAdapter.removeSelection(position);
}
mode.setTitle(nr + " rows selected!");
}
});
}
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
l.setItemChecked(position, !mAdapter.isPositionChecked(position));
}
private class SelectionAdapter extends ArrayAdapter<String> {
private HashMap<Integer, Boolean> mSelection = new HashMap<Integer, Boolean>();
public SelectionAdapter(Context context, int resource,
int textViewResourceId, List<String> objects) {
super(context, resource, textViewResourceId, objects);
}
public void setNewSelection(int position, boolean value) {
mSelection.put(position, value);
notifyDataSetChanged();
}
public boolean isPositionChecked(int position) {
Boolean result = mSelection.get(position);
return result == null ? false : result;
}
public Set<Integer> getCurrentCheckedPosition() {
return mSelection.keySet();
}
public void removeSelection(int position) {
mSelection.remove(position);
notifyDataSetChanged();
}
public void clearSelection() {
mSelection = new HashMap<Integer, Boolean>();
notifyDataSetChanged();
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = super.getView(position, convertView, parent);//let the adapter handle setting up the row views
v.setBackgroundColor(Color.parseColor("#99cc00")); //default color
if (mSelection.get(position) != null) {
v.setBackgroundColor(Color.RED);// this is a selected position so make it red
}
return v;
}
}
}
Another way
adapter = new MyListAdapter(this);
lv = (ListView) findViewById(android.R.id.list);
lv.setAdapter(adapter);
lv.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> a, View v, int position, long id) {
AlertDialog.Builder adb=new AlertDialog.Builder(MyActivity.this);
adb.setTitle("Delete?");
adb.setMessage("Are you sure you want to delete " + position);
final int positionToRemove = position;
adb.setNegativeButton("Cancel", null);
adb.setPositiveButton("Ok", new AlertDialog.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
MyDataObject.remove(positionToRemove);
adapter.notifyDataSetChanged();
}});
adb.show();
}
});
getView(final int i,
Do not make i final. You did that to use i in onClick(). But that is not possible. So remove the final. Add:
holder.btnRemove.setTag(i);
And in onClick:
int position = v.getTag();
..deleteUser(position);
Maybe you have to cast something somewhere..
Remark: You have to set the tag always. So do it just before return view;.
Please do not use an i for position.
I have used this implementation of a multi select spinner I found here on StackOverflow:
package cz.destil.settleup.gui;
public class MultiSpinner extends Spinner implements
OnMultiChoiceClickListener, OnCancelListener {
private List<String> items;
private boolean[] selected;
private String defaultText;
private MultiSpinnerListener listener;
public MultiSpinner(Context context) {
super(context);
}
public MultiSpinner(Context arg0, AttributeSet arg1) {
super(arg0, arg1);
}
public MultiSpinner(Context arg0, AttributeSet arg1, int arg2) {
super(arg0, arg1, arg2);
}
#Override
public void onClick(DialogInterface dialog, int which, boolean isChecked) {
if (isChecked)
selected[which] = true;
else
selected[which] = false;
}
#Override
public void onCancel(DialogInterface dialog) {
// refresh text on spinner
StringBuffer spinnerBuffer = new StringBuffer();
boolean someUnselected = false;
for (int i = 0; i < items.size(); i++) {
if (selected[i] == true) {
spinnerBuffer.append(items.get(i));
spinnerBuffer.append(", ");
} else {
someUnselected = true;
}
}
String spinnerText;
if (someUnselected) {
spinnerText = spinnerBuffer.toString();
if (spinnerText.length() > 2)
spinnerText = spinnerText.substring(0, spinnerText.length() - 2);
} else {
spinnerText = defaultText;
}
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getContext(),
android.R.layout.simple_spinner_item,
new String[] { spinnerText });
setAdapter(adapter);
listener.onItemsSelected(selected);
}
#Override
public boolean performClick() {
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setMultiChoiceItems(
items.toArray(new CharSequence[items.size()]), selected, this);
builder.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
builder.setOnCancelListener(this);
builder.show();
return true;
}
public void setItems(List<String> items, String allText,
MultiSpinnerListener listener) {
this.items = items;
this.defaultText = allText;
this.listener = listener;
// all selected by default
selected = new boolean[items.size()];
for (int i = 0; i < selected.length; i++)
selected[i] = true;
// all text on the spinner
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getContext(),
android.R.layout.simple_spinner_item, new String[] { allText });
setAdapter(adapter);
}
public interface MultiSpinnerListener {
public void onItemsSelected(boolean[] selected);
}
}
Now I want to change the design of the window that opens when I click on this Multispinner button, I tried to change this: android.R.layout.simple_spinner_item to my own layout but this changed only the button that open the spinner, not the items inside it.
How can I change the design on the inner multispinner items?
Thanks.
The dialog that is shown is created in the performClick() method. However, it doesn't look like you could change the layout of the list items here, as the setMultiChoiceItems(...) method does not support it.
So you will need to implement a custom view for your dialog, which you can set in the setView(...) method (example). And you will also have to implement the onClick() method by yourself then.
Update: Maybe the better way is using the setAdapter(...) method. This way you can just use your own list adapter, so you can style the items the way you want. And this method does also provide an onclick listener argument. So it may be simpler.
Update 2: I tried a bit myself, and this is what I came up with. I added a comment, where you can insert your own view:
public class MultiSpinner extends Spinner implements OnCancelListener,
OnItemClickListener {
public class MultiSpinnerListAdapter extends BaseAdapter {
#Override
public int getCount() {
return items.size();
}
#Override
public String getItem(int position) {
return items.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO: Update the following to use your own custom view.
if (convertView == null) {
convertView = activity.getLayoutInflater().inflate(
android.R.layout.simple_list_item_multiple_choice,
parent, false);
}
CheckedTextView textView = (CheckedTextView) convertView;
textView.setText(items.get(position));
textView.setChecked(selected[position]);
return convertView;
}
}
private MultiSpinnerListAdapter adapter;
private Activity activity;
private List<String> items;
private boolean[] selected;
private String defaultText;
private MultiSpinnerListener listener;
public MultiSpinner(Context context) {
super(context);
}
public MultiSpinner(Context arg0, AttributeSet arg1) {
super(arg0, arg1);
}
public MultiSpinner(Context arg0, AttributeSet arg1, int arg2) {
super(arg0, arg1, arg2);
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
CheckedTextView textView = (CheckedTextView) view;
textView.setChecked(!textView.isChecked());
selected[position] = textView.isChecked();
}
#Override
public void onCancel(DialogInterface dialog) {
// refresh text on spinner
StringBuffer spinnerBuffer = new StringBuffer();
boolean someUnselected = false;
for (int i = 0; i < items.size(); i++) {
if (selected[i] == true) {
spinnerBuffer.append(items.get(i));
spinnerBuffer.append(", ");
} else {
someUnselected = true;
}
}
String spinnerText;
if (someUnselected) {
spinnerText = spinnerBuffer.toString();
if (spinnerText.length() > 2)
spinnerText = spinnerText
.substring(0, spinnerText.length() - 2);
} else {
spinnerText = defaultText;
}
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getContext(),
android.R.layout.simple_spinner_item,
new String[] { spinnerText });
setAdapter(adapter);
listener.onItemsSelected(selected);
}
#Override
public boolean performClick() {
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setAdapter(adapter, null);
builder.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
builder.setOnCancelListener(this);
AlertDialog dialog = builder.create();
dialog.getListView().setOnItemClickListener(this);
dialog.show();
return true;
}
public void setItems(Activity activity, List<String> items, String allText,
MultiSpinnerListener listener) {
this.adapter = new MultiSpinnerListAdapter();
this.activity = activity;
this.items = items;
this.defaultText = allText;
this.listener = listener;
// all selected by default
selected = new boolean[items.size()];
for (int i = 0; i < selected.length; i++)
selected[i] = true;
// all text on the spinner
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getContext(),
android.R.layout.simple_spinner_item, new String[] { allText });
setAdapter(adapter);
}
public interface MultiSpinnerListener {
public void onItemsSelected(boolean[] selected);
}
}
Spinner with checkbox items, is it possible?
Try this
<selva.spinner.multispinner android:id="#+id/multi_spinner"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
Spinner1Activity.java
package selva.spinner;
import java.util.ArrayList;
import java.util.List;
import selva.spinner.multispinner.multispinnerListener;
import android.app.Activity;
import android.os.Bundle;
public class Spinner1Activity extends Activity implements multispinnerListener
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
multispinner ms = (multispinner) findViewById(R.id.multi_spinner);
List<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
list.add("four");
list.add("five");
list.add("six");
list.add("seven");
list.add("eight");
list.add("nine");
list.add("ten");
ms.setItems(list, "select", this);
}
#Override
public void onItemschecked(boolean[] checked)
{
// TODO Auto-generated method stub
}
}
multispinner.java
package selva.spinner;
import java.util.List;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.DialogInterface.OnMultiChoiceClickListener;
import android.util.AttributeSet;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
public class multispinner extends Spinner implements
OnMultiChoiceClickListener, OnCancelListener
{
private List<String> listitems;
private boolean[] checked;
public multispinner(Context context)
{
super(context);
}
public multispinner(Context arg0, AttributeSet arg1)
{
super(arg0, arg1);
}
public multispinner(Context arg0, AttributeSet arg1, int arg2)
{
super(arg0, arg1, arg2);
}
#Override
public void onClick(DialogInterface dialog, int ans, boolean isChecked)
{
if (isChecked)
checked[ans] = true;
else
checked[ans] = false;
}
#Override
public void onCancel(DialogInterface dialog)
{
String str="Selected values are: ";
for (int i = 0; i < listitems.size(); i++)
{
if (checked[i] == true)
{
str=str+" "+listitems.get(i);
}
}
AlertDialog.Builder alert1 = new AlertDialog.Builder(getContext());
alert1.setTitle("Items:");
alert1.setMessage(str);
alert1.setPositiveButton("Ok", null);
alert1.show();
}
#Override
public boolean performClick()
{
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setMultiChoiceItems(
listitems.toArray(new CharSequence[listitems.size()]), checked, this);
builder.setPositiveButton("done",
new DialogInterface.OnClickListener()
{
#Override
public void onClick(DialogInterface dialog, int which)
{
dialog.cancel();
}
});
builder.setOnCancelListener(this);
builder.show();
return true;
}
public void setItems(List<String> items, String allText,
multispinnerListener listener)
{
this.listitems = items;
checked = new boolean[items.size()];
for (int i = 0; i < checked.length; i++)
checked[i] =false;
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getContext(),
android.R.layout.simple_spinner_item, new String[] { allText });
setAdapter(adapter);
}
public interface multispinnerListener
{
public void onItemschecked(boolean[] checked);
}
}
That depends on what you mean.
If you want a true multi-select Spinner, then there's nothing built into Android for that.
Note that you are in control over what goes in the Spinner rows of the drop-down list, except for the radio button. If you want to put checkboxes in your rows, be my guest. It'll look strange, may not work properly with respect to touch events, will not remove the radio buttons (AFAIK), and will be completely unrelated to the Spinner's contents in normal mode. Hence, I can't recommend this approach, but it is doable.
The source code to Spinner is available from the Android open source project, so you are welcome to clone it and develop a MultiSelectSpinner or something.
You can use the multiSpinner:
import java.util.List;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.DialogInterface.OnMultiChoiceClickListener;
import android.util.AttributeSet;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
public class MultiSpinner extends Spinner implements OnMultiChoiceClickListener, OnCancelListener {
private List<String> items;
private boolean[] selected;
private String defaultText;
private MultiSpinnerListener listener;
public MultiSpinner(Context context) {
super(context);
}
public MultiSpinner(Context arg0, AttributeSet arg1) {
super(arg0, arg1);
}
public MultiSpinner(Context arg0, AttributeSet arg1, int arg2) {
super(arg0, arg1, arg2);
}
#Override
public void onClick(DialogInterface dialog, int which, boolean isChecked) {
if (isChecked)
selected[which] = true;
else
selected[which] = false;
}
#Override
public void onCancel(DialogInterface dialog) {
// refresh text on spinner
StringBuffer spinnerBuffer = new StringBuffer();
boolean someUnselected = false;
for (int i = 0; i < items.size(); i++) {
if (selected[i] == true) {
spinnerBuffer.append(items.get(i));
spinnerBuffer.append(", ");
} else {
someUnselected = true;
}
}
String spinnerText;
if (someUnselected) {
spinnerText = spinnerBuffer.toString();
if (spinnerText.length() > 2)
spinnerText = spinnerText.substring(0, spinnerText.length() - 2);
} else {
spinnerText = defaultText;
}
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getContext(),
android.R.layout.simple_spinner_item,
new String[] { spinnerText });
setAdapter(adapter);
listener.onItemsSelected(selected);
}
#Override
public boolean performClick() {
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setMultiChoiceItems(
items.toArray(new CharSequence[items.size()]), selected, this);
builder.setPositiveButton(R.string.ok,
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
builder.setOnCancelListener(this);
builder.show();
return true;
}
public void setItems(List<String> items, String allText,
MultiSpinnerListener listener) {
this.items = items;
this.defaultText = allText;
this.listener = listener;
// all selected by default
selected = new boolean[items.size()];
for (int i = 0; i < selected.length; i++)
selected[i] = true;
// all text on the spinner
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getContext(),
android.R.layout.simple_spinner_item, new String[] { allText });
setAdapter(adapter);
}
public interface MultiSpinnerListener {
public void onItemsSelected(boolean[] selected);
}
}
And then in your layout .xml:
<xxx.xx.gui.MultiSpinner android:id="#+id/SpinnerCollegues"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:prompt="#string/university"/>
You could just create a ListView with check boxes. You could even add it to a dialog. That's essentially all a spinner is.
There is implemented a MultiSpinner, you can find it on AndroidArsenal
Can find it on Maven Repository
If you add a hint to it, looks nice:
android:hint="Choose ..."
I created a dynamic filled Spinner which gets its content over the Sqlite Database query over the content resolver, it's a Image instead of text when closed, it shows whats selected, and its awesome simple :-)
spinnerFavorites = (SpinnerMultiSameClick) v.findViewById(R.id.guide_btn_favorites);
spinnerFavorites.setOnItemSelectedListener(this);
ContentResolver resolver = activity.getContentResolver();
String[] projection = new String[] { DataContract.Favorites.FAVORITES_ID, DataContract.Favorites.NAME };
Cursor cursor = resolver.query(DataContract.Favorites.CONTENT_URI, projection, null, null, DataContract.Favorites.FAVORITES_ID +" ASC");
if (cursor.getCount() > 0) {
// create an array to specify which fields we want to display
String[] from = new String[] { DataContract.Favorites.NAME, DataContract.Favorites.FAVORITES_ID };
// create an array of the display item we want to bind our data
// to
int[] to = new int[] { android.R.id.text1, android.R.id.text2 };
SimpleCursorAdapter adapter = new SimpleCursorAdapter(activity, R.layout.ghost_text, cursor, from, to,
SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
// get reference to our spinner
spinner.setAdapter(adapter);
adapter.setDropDownViewResource(android.R.layout.simple_list_item_single_choice);
} else {
// TODO: Maybe button to make new favList
spinnerFavorites.setVisiblity(View.GONE);
}
Now, it looks like a simple Spinner, what makes it show its selection is this line, it will fill the values and put a radioCheckbox on the right side, the top/1st Element in your list will be preselected.
adapter.setDropDownViewResource(android.R.layout.simple_list_item_single_choice);
there are several other predefined layouts wich work pretty well
simple_list_item_checked -> shows a checkMark instead of a RadioButton
simple_list_item_activated_1 or 2 -> Changes BackgroundColor
simple_list_item_multiple_choice -> CheckBoxes with checkMarks
to complete here is my layout, it shows an marked or unmarked Image (and not whats selected) therefore i specified R.layout.ghost_text in the spinnerAdapter.
<com.netstream.ch.tv.android.ui.program.guide.land.SpinnerMultiSameClick
android:id="#+id/guide_btn_favorites"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:background="#drawable/icon_selector_guide_filter_favorites"
android:clickable="true" />
here my onItemSelecte which needs the OnItemSelectedListener Interfaces. What it does, it keeps track with a boolean if its the initialisation of the spinner or not. If there is a real click, we extract the information and update another UI Element over a Controller (could also be a callback) if the Clicked Element is the StandardSelected Element i set the SpinnerImage unselected, if its sth else then the standard element i set the spinnerImage selected.
#Override
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
if (parent.getId() == R.id.guide_btn_favorites) {
if (!AbsintheViewControllerFactory.getGuideController().isFavoriteListInitialisation()) {
Cursor c = (Cursor) parent.getItemAtPosition(pos);
String favid = c.getString(c.getColumnIndexOrThrow(DataContract.Favorites.FAVORITES_ID));
String name = c.getString(c.getColumnIndexOrThrow(DataContract.Favorites.NAME));
Log.d(TAG, "Set Filter to FavListId: " + favid + " by its name: " + name);
if (favid.equalsIgnoreCase(GuideViewController.allChannelsFavoritesIdentifier)) {
spinnerFavorites.setSelected(false);
} else {
spinnerFavorites.setSelected(true);
}
AbsintheViewControllerFactory.getGuideController().setFavourites(favid);
guideInfoSelectedFavoriteList.setText(name);
} else {
AbsintheViewControllerFactory.getGuideController().setFavoriteListInitialisation(false);
guideInfoSelectedFavoriteList.setText(getActivity().getResources().getString(R.string.FILTER_FAVORITE_ALL_CHANNELS));
}
}
}