Reputation: 2365
I have two spinners, such that my second spinner changes options that it can offer according to the item selected in the first spinner. Easy?
Example: If I select 'a' in main spinner, the sub spinner should show 'a1' as option. If I select 'b' in main spinner, the sub spinner should show 'b1','b2' as options. If I select 'c' in main spinner, the sub spinner should show 'c1','c2','c3' as options.
I use a library called SearchableSpinner but that does not matter as it works just like the Android spinner.
public class PostComplaint extends AppCompatActivity {
String[] problems_main = {"a","b","c"};
String[][] problems_sub = {{"a1"},{"b1","b2"},{"c1","c2","c3"}};
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_post_complaint);
spinner_main = (SearchableSpinner)findViewById(R.id.spinner_main);
spinner_sub = (SearchableSpinner) findViewById(R.id.spinner_sub);
ArrayAdapter<String> spinnerAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, problems_main);
spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner_main.setAdapter(spinnerAdapter);
spinnerAdapter.notifyDataSetChanged();
spinner_main.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
setSubSpinner(position);
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
Toast.makeText(PostComplaint.this, "Nothing selected", Toast.LENGTH_SHORT).show();
}
});
}
void setSubSpinner(int i){
String[] myArray = problems_sub[i]; //Note: problems_sub is a two dimensional array
ArrayAdapter<String> spinnerAdapter_sub = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, myArray);
spinnerAdapter_sub.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner_sub.setAdapter(spinnerAdapter_sub);
spinnerAdapter_sub.notifyDataSetChanged();
}
Problem: Whichever item I click on the main spinner for the first time, according to that the sub spinner is selected. Then if I change the main spinner, the sub spinner is not changing.
The question is open for suggestions. Comment if it is not understandable.
Upvotes: 4
Views: 688
Reputation: 749
The error is coming because of the following function in the SearchableSpinner Class:
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
ArrayAdapter adapter = (ArrayAdapter) getAdapter();
if (null != adapter) {
if (_items.size() == 0) {
for (int i = 0; i < adapter.getCount(); i++) {
_items.add(adapter.getItem(i));
}
}
SearchableListDialog searchableListDialog = SearchableListDialog.newInstance
(_items);
searchableListDialog.setOnSearchableItemClickListener(this);
searchableListDialog.show(((Activity) _context).getFragmentManager(), "TAG");
}
}
return true;
}
The condition if(_items.size() == 0)
becomes true only the first time you click on the sub spinner and hence it gets initialized correctly and you will see correct values. However, once you have clicked on the sub spinner, _item.size()
will never be zero and thus, the updated sub spinner values will never be rendered.
I suggest you use the default Android Spinner or fork the repository and fix the error and use the same.
EDIT
You can try using this class:
import android.app.Activity;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import com.toptoche.searchablespinnerlibrary.SearchableListDialog;
import java.util.ArrayList;
import java.util.List;
public class CustomSearchableSpinner extends Spinner implements View.OnTouchListener,
SearchableListDialog.SearchableItem {
private Context _context;
private List _items;
private boolean isDataSetChanged;
public CustomSearchableSpinner(Context context) {
super(context);
this._context = context;
this.isDataSetChanged = true;
init();
}
public CustomSearchableSpinner(Context context, AttributeSet attrs) {
super(context, attrs);
this._context = context;
this.isDataSetChanged = true;
init();
}
public CustomSearchableSpinner(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this._context = context;
this.isDataSetChanged = true;
init();
}
private void init() {
_items = new ArrayList();
setOnTouchListener(this);
}
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
ArrayAdapter adapter = (ArrayAdapter) getAdapter();
if (null != adapter) {
if (isDataSetChanged) {
if(_items.size() != 0) {
_items = new ArrayList();
}
for (int i = 0; i < adapter.getCount(); i++) {
_items.add(adapter.getItem(i));
}
isDataSetChanged = false;
}
SearchableListDialog searchableListDialog = SearchableListDialog.newInstance
(_items);
searchableListDialog.setOnSearchableItemClickListener(this);
searchableListDialog.show(((Activity) _context).getFragmentManager(), "TAG");
}
}
return true;
}
@Override
public void onSearchableItemClicked(Object item, int position) {
setSelection(_items.indexOf(item));
}
public void notifyDataChanged(Boolean hasDataChanged) {
this.isDataSetChanged = hasDataChanged;
}
}
Also, update your layout file and PostComplaint Class to use CustomSearchableSpinner in place of Searchable Spinner. It may not be the best approach, but it works.
EDIT 2
You will need to call spinnerAdapter_sub.notifyDataChanged(true)
after you call spinnerAdapter_sub.notifyDataSetChanged();
.
Upvotes: 1