Reputation: 95
I'm integrating searchable spinner in my app. Below is my code
gradle file
compile 'com.toptoche.searchablespinner:searchablespinnerlibrary:1.3.1'
Xml file
<com.toptoche.searchablespinnerlibrary.SearchableSpinner
android:id="@+id/spinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:hintText="Select Country"/>
Man.java
public class MainActivity extends AppCompatActivity {
SearchableSpinner mSearchableSpinner;
ArrayList<GetCountry> mGetCountries;
PriorityAdapter mPriorityAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mSearchableSpinner = (SearchableSpinner) findViewById(R.id.spinner);
mGetCountries = new ArrayList<>();
GetCountry mGetCountry = new GetCountry();
mGetCountry.setId("1");
mGetCountry.setName("India");
mGetCountries.add(mGetCountry);
GetCountry mGetCountry2 = new GetCountry();
mGetCountry2.setId("2");
mGetCountry2.setName("USA");
mGetCountries.add(mGetCountry2);
GetCountry mGetCountry3 = new GetCountry();
mGetCountry3.setId("3");
mGetCountry3.setName("UK");
mGetCountries.add(mGetCountry3);
GetCountry mGetCountry4 = new GetCountry();
mGetCountry4.setId("4");
mGetCountry4.setName("CHINE");
mGetCountries.add(mGetCountry4);
GetCountry mGetCountry5 = new GetCountry();
mGetCountry5.setId("5");
mGetCountry5.setName("MALASIYA");
mGetCountries.add(mGetCountry5);
mPriorityAdapter=new PriorityAdapter(mGetCountries);
mSearchableSpinner.setAdapter(mPriorityAdapter);
}
public class PriorityAdapter extends ArrayAdapter<GetCountry> {
ArrayList<GetCountry> list;
public PriorityAdapter(ArrayList<GetCountry> list) {
super(MainActivity.this, R.layout.spin_layout, list);
this.list = list;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) { // Ordinary
return initView(position, convertView, parent);
}
@Override
public View getDropDownView(int position, View convertView,
ViewGroup parent) { // This view starts when we click the
// spinner.
return initView(position, convertView, parent);
}
public View initView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflator = getLayoutInflater();
convertView = inflator.inflate(R.layout.spin_layout, null);
TextView mTextView = (TextView) convertView
.findViewById(android.R.id.text1);
mTextView.setText(list.get(position).getName());
return convertView;
}
}
}
When i run above code i m getting output like below image. Custom arraylist data not display it is print garbage value of java every item Spinner Output
Any idea how can i solve this?
EDIT
public class PriorityAdapter extends ArrayAdapter<GetCountry> {
ArrayList<GetCountry> list;
public PriorityAdapter(ArrayList<GetCountry> list) {
super(MainActivity.this, R.layout.spin_layout, list);
this.list = list;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) { // Ordinary
return initView(position, convertView, parent);
}
@Nullable
@Override
public GetCountry getItem(int position) {
return super.getItem(position);
}
@Override
public View getDropDownView(int position, View convertView,
ViewGroup parent) { // This view starts when we click the
View view = convertView;
LayoutInflater layoutInflater = LayoutInflater.from(getContext());
view = layoutInflater.inflate(R.layout.spin_layout_1, parent, false);
TextView tv= (TextView) view.findViewById(R.id.text1);
tv.setText(list.get(position).getName());
return view;
}
public View initView(int position, View convertView, ViewGroup parent) {
View view = convertView;
LayoutInflater layoutInflater = LayoutInflater.from(getContext());
view = layoutInflater.inflate(R.layout.spin_layout_1, parent, false);
TextView tv= (TextView) view.findViewById(R.id.text1);
tv.setText(list.get(position).getName());
return view;
}
}
GetCountry.java
public class GetCountry {
String name;
String id;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
Upvotes: 4
Views: 5186
Reputation: 1080
There is a solution, but it is bad LoL. If you look to the searchableSpinner Library it calls the ArrayAdapter base class and not the ArrayAdapter class you setted. So..
Or you re-implement the library and then you use a "generic Object which extends ArrayAdapter class" so it will use your getDropDownView.
Or, if you look to ArrayAdapter base class you can find this code which is the one it is used to display to "toString" of your items in the adapter:
private @NonNull View createViewFromResource(@NonNull LayoutInflater inflater, int position,
@Nullable View convertView, @NonNull ViewGroup parent, int resource) {
final View view;
final TextView text;
if (convertView == null) {
view = inflater.inflate(resource, parent, false);
} else {
view = convertView;
}
try {
if (mFieldId == 0) {
// If no custom field is assigned, assume the whole resource is a TextView
text = (TextView) view;
} else {
// Otherwise, find the TextView field within the layout
text = view.findViewById(mFieldId);
if (text == null) {
throw new RuntimeException("Failed to find view with ID "
+ mContext.getResources().getResourceName(mFieldId)
+ " in item layout");
}
}
} catch (ClassCastException e) {
Log.e("ArrayAdapter", "You must supply a resource ID for a TextView");
throw new IllegalStateException(
"ArrayAdapter requires the resource ID to be a TextView", e);
}
final T item = getItem(position);
if (item instanceof CharSequence) {
text.setText((CharSequence) item);
} else {
text.setText(item.toString());
}
return view;
}
As you can see in last lines:
final T item = getItem(position);
if (item instanceof CharSequence) {
text.setText((CharSequence) item);
} else {
text.setText(item.toString());
}
So it will call the onString method if it isn't a CharSequence. Then: or you override the onString method of your object (I don't like this solution because I often use the onString for debugging purposes on the debugger) or you implement 2 arrays in your custom adapter:
1 array of CharSequences with the values to display
1 array with your objects
You ArrayAdapter will be a simple "ArrayAdapter<String>" and not "ArrayAdapter<YourObject>" (this is why it isn't the best solution: you will lose all "ArrayAdapter" generic objects structure benefits.).
Your "getItem" method will return the object in the String List, then you will use the position to retrieve your item from the other array stored in the adapter.
This will require another step and public method inside of you adapter. So when you use "getSelectedItem" it will return you the label instead of the object, so to get the real "selectedObject" you should call "getSelectedItemPosition" and pass it to the method which returns the real object using the position.
You can pass your custom items list in the addAll method overrided (not in the constructor...) of your custom adapter. Inside that you will create your list of CharSequences (or Strings) which will be only used for visualization purpose. I mean something like this:
public void addAll(List<YourObject> myObjects){
mItems.clear() // mItems => List<YourObject>
mLabels.clear() // mLabels => List<String> (so labels visualized)
if(myObjects != null && myObjects.size > 0x0{
mItems.addAll(myObjects);
for(YourObject obj : myObjects){
mLabels.add(obj.getMyLabel());
}
}
notifyDataSetChanged()
}
(I wrote all the code on the fly here in stackoverflow so sorry if there are any errors)
This is the faster solution I found without changing the "onString" methods of my objects, the better one is to re-implement the searchable spinner library, if you have time, to use custom ArrayAdapter and not only the base class ArrayAdapter.
Summarizing:
gg, have an happy coding
I did a BaseSearchableSpinnerAdapter class using the logic above, here the code:
public abstract class BaseSearchableSpinnerAdapter<T extends Object> extends ArrayAdapter<String> {
protected Context mContext;
protected List<String> mLabels;
protected List<T> mItems;
public BaseSearchableSpinnerAdapter(@NonNull Context context, int resource) {
super(context, resource);
mContext = context;
mItems = new ArrayList<>();
mLabels = new ArrayList<>();
}
/** Abstract Methods **/
public abstract String getLabel(int pos); //used to get the label to view
/** Override ArrayAdapter Methods **/
@NonNull
@Override
public View getView(int position, View convertView, @NonNull ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.spinner_default, parent, false);
}
TextView tv = convertView.findViewById(R.id.text1);
if(tv != null){
tv.setText(getLabel(position));
}
return convertView;
}
@Override
public int getCount(){
return mLabels.size();
}
@Override
public String getItem(int position){
return mLabels.get(position);
}
@Override
public long getItemId(int position){
return position;
}
/** Public Methods **/
public void clear(){
mLabels.clear();
mItems.clear();
}
public void addAll(List<T> objs){
mLabels.clear();
mItems.clear();
if(objs != null && objs.size() > 0x0){
mItems.addAll(objs);
for(int i=0x0; i<objs.size(); i++){
mLabels.add(getLabel(i));
}
}
notifyDataSetChanged();
}
public T getMyItem(int pos){
return mItems.get(pos);
}
}
I used generic object (the ) because it doesn't require the cast when you retrieve your object. You can also use base class like "Object" or may "" (Didn't check last one), but in this case you need to cast it.
Extends by doing:
public class MyClassSearchableSpinnerAdapter extends BaseSearchableSpinnerAdapter<MyObject>;
Instead of do:
YourObject myobj = mSpinner.getSelectedItem();
You must to do:
YourObject myObj = ((MyClassSearchableSpinnerAdapter) mSpinner.getAdapter()).getMyItem(mSpinner.getSelectedItemPosition());
Hope this is helpful, bb have a nice coding. In the searchable spinners views (dropdown and selected) you will see what you returns in the "getLabel()" method.
Upvotes: 1
Reputation: 57
You can override toString() function of your model (GetCountry) like so:
GetCountry.java
public class GetCountry {
String name;
String id;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@Override
public String toString() {
return name;
}
}
Upvotes: 4
Reputation: 1630
You are getting this list because your getView and any other method declared in the PriorityAdapter is not calling at all. So why to use a custom Adapter,instead just go for the simple array adapter as below -
String[] names = new String[]{"India","CHINA","UK","US","MALYSIA"};
ArrayAdapter arrayAdapter = new ArrayAdapter(SearchActivity.this,android.R.layout.simple_spinner_dropdown_item,names);
mSearchableSpinner.setAdapter(arrayAdapter);
Add these lines in onCreate Method of activity and you will get your proper dropdown.
Upvotes: 0
Reputation: 98
you can try to change getView and getDropDownView return value
like this;
View view = convertView;
LayoutInflater layoutInflater = LayoutInflater.from(getContext());
view = layoutInflater.inflate(R.layout.spinneradapter, parent, false);
TextView tv= (TextView) view.findViewById(R.id.tvEkipCantasiEkipman);
tvAdet.setText(arrayListItem);
return view;
Upvotes: 1