I have spinner and my custom spinner adapter.
In some reasons spinner (when user change item selection) dont fire OnItemSelected in my adapter and does not call getView so i cannt render currently selected item ( spinner firing internal item click and set current item correctly)
If User open "software keyboard" spinner works perfectly! It always refreshing spinner content.
I can provide more info if necessary
Any suggestion ?
public class DictionarySpinnerAdapter implements SpinnerAdapter, OnItemSelectedListener{
public DictionarySpinnerAdapter(BaseActivity ctx, Spinner owner)
{
this.ctx = ctx;
li = (LayoutInflater) ctx.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
Owner = owner;
Owner.setClickable(true);
Owner.setOnItemSelectedListener(this);
}
#Override
public int getCount() {
return (dictionaries == null ) ? 0 : dictionaries.size() + offset ;
}
#Override
public Object getItem(int position) {
if ( position > (offset - 1) )
return dictionaries.get(position - offset);
else
return null;
}
#Override
public long getItemId(int position) {
if ( position > (offset - 1) )
return dictionaries.get(position-offset).GetKey();
else
return -1;
}
#Override
public int getItemViewType(int position) {
return 1;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
//rendering my items...
}
#Override
public boolean hasStableIds() {
return true;
}
#Override
public boolean isEmpty() {
return ( dictionaries != null ) ? false : true;
}
#Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
//rendering dropdowns
}
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position,
long id) {
SetSelectedItem((int)id);
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
SetSelectedItem(null);
}
public void SetSelectedItem(Integer byKey)
{
if ( byKey == null|| (byKey == -1 && allowNull))
{
selectedPosition = 0;
if ( allowNull)
selectedKey = -1;
else
if (dictionaries!=null&& dictionaries.size()>0)
selectedKey = dictionaries.get(0).GetKey();
if (selectedKey > -1)
firstSelected = true;
handleItemClick(selectedKey);
Owner.setSelection(selectedPosition);
return;
}
for(Dictionary entry : dictionaries )
if ( entry.GetKey() == byKey.intValue() )
{
selectedKey = byKey;
selectedPosition = dictionaries.indexOf(entry) + offset;
handleItemClick(selectedKey);
break;
}
// Log.i("MAH", "setSelectedItem("+selectedPosition+")");
firstSelected = true;
Owner.setSelection(selectedPosition);
}
}
EDIT:
After some debugging i think in this code (Absspinner.java) is problem.
#Override
public void setSelection(int position) {
setNextSelectedPositionInt(position); //works fine
requestLayout(); // ??
invalidate(); // ??
}
EDIT2:
Spinner is inside TableLayout if I move it outside tablelayout its works fine. So my new question is: how i can refresh view inside TableLayout ?
Related
This is the first grid where I selected
the problem is:
when I scroll down, here random images are getting selected
I used glide library for grid view. Here's the Java Code for Multiple selection:
mgridview.setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() {
#Override
public void onItemCheckedStateChanged(ActionMode actionMode, int i, long l, boolean b) {
if (sel_tab2_images.contains(tab2_images.get(i))) {
sel_count = sel_count - 1;
actionMode.setTitle(sel_count + " images selected");
sel_tab2_images.remove(tab2_images.get(i));
viewprev = mgridview.getChildAt(i - mgridview.getFirstVisiblePosition());
viewprev.setBackgroundColor(Color.WHITE);
viewprev.setAlpha(1f);
if(Build.VERSION.SDK_INT>=23) {
viewprev.setForeground(null);
}
} else {
sel_count = sel_count + 1;
actionMode.setTitle(sel_count + " images selected");
sel_tab2_images.add(tab2_images.get(i));
viewprev = mgridview.getChildAt(i - mgridview.getFirstVisiblePosition());
if (viewprev != null) {
viewprev.setAlpha(0.5f);
//ImageView imageView=viewprev.findViewById(R.id.tick);
//Resource(R.drawable.ic_save_black_24dp);
if(Build.VERSION.SDK_INT>=23) {
viewprev.setForeground(getResources().getDrawable(R.drawable.ic_check_white_24dp));
}
}
else
Toast.makeText(getContext(), "Error Occured", Toast.LENGTH_SHORT).show();
}
}
#Override
public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
MenuInflater inflater = actionMode.getMenuInflater();
inflater.inflate(R.menu.context_action_bar, menu);
return true;
}
#Override
public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
return false;
}
#Override
public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
int del_count = 0;
switch (menuItem.getItemId()) {
case R.id.delete_action_bar:
for (String sel : sel_tab2_images) {
file = new File(sel);
if (file.exists()) {
file.delete();
tab2_images.remove(sel);
if (tab1_fragment.tab1_images.contains(sel)) {
tab1_fragment.tab1_images.remove(sel);
}
if (tab3_fragment.spam_list.contains(sel)) {
tab3_fragment.spam_list.remove(sel);
}
UpdateGallery(sel);
/*
int pos_1=tab2_images.indexOf(sel);
tab2_images.remove(sel);
adapter.notifyDataSetChanged();
viewprev=mgridview.getChildAt(pos_1);
viewprev.setBackgroundColor(Color.WHITE);
*/
del_count++;
}
}
adapter = new ImageAdapterGridView(getContext());
mgridview.setAdapter(adapter);
Toast.makeText(getContext(), del_count + " images deleted", Toast.LENGTH_SHORT).show();
sel_count = 0;
sel_tab2_images.clear();
actionMode.finish();
break;
}
return true;
}
#Override
public void onDestroyActionMode(ActionMode actionMode) {
}
});
return view;
}
Below is the java code for Grid View. I also tried #overriding getItem and getItemId methods but it's not working. This is my first app and I'm still learning. Please help me to fix this!
public class ImageAdapterGridView extends BaseAdapter {
private Context mcontext;
public ImageAdapterGridView(Context c) {
mcontext = c;
}
public int getCount() {
return tab2_images.size();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertview, ViewGroup parent) {
ImageView imageView;
if(convertview==null){
imageView= new ImageView(mcontext);
imageView.setLayoutParams(new GridView.LayoutParams(280,320));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setPadding(16,16,16,16);
}
else{
imageView=(ImageView)convertview;
}
Glide.with(tab2_fragment.this).load("file://" + tab2_images.get(position))
.diskCacheStrategy(DiskCacheStrategy.RESULT)
.skipMemoryCache(true)
.into(imageView);
return imageView;
}
}
#Override
public void onResume() {
super.onResume();
adapter = new ImageAdapterGridView(getContext());
mgridview.setAdapter(adapter);
}
}
You're relying on view in a list. In list views are being reused as they get off screen. So to get this done you have to declare a boolean isSelected per each item (so the best place to do this is in your item model which holds all each grid properties) and make it true as the user select your grid item and always update your view based on that boolean not the view.
Currently your model is holding just the url of your images. If you need to save the isSelected boolean there you should build your model object like:
public class ImageModel {
public String url;
public boolean isSelected;
}
And then use the field objects in your grid list:
public void onItemCheckedStateChanged(ActionMode actionMode, int i, long l, boolean b) {
ImageModel image = tab2_images.get(i);
if (image.isSelected) {
// Image is selected you need to deselect it
} else {
// Image is not selected you need to select it
}
}
In your adapter:
public View getView(int position, View convertview, ViewGroup parent) {
// Your view construction code
ImageModel image = tab2_images.get(i);
if (image.isSelected) {
// Show your check image view
} else {
// Image is not selected yet, hide your check image view
}
}
I hope this helps but grid view is considered deprecated, try to consider using RecyclerView which is more efficient and fast.
I'm trying to create ListView with installed apps. User selects apps inside wizard (basically viewpager).
My plan is to create a list of custom views (icon, name, package) that will allow to select more than one item. Unfortunatelly checkboxes won't work, because I need this place for another functionality. So, I'll change the background of the element.
So, I found a solution on stackoverflow and changed it a bit.
Firstly - main activity with this list.
public class MainActivity extends ListActivity {
private static final String TAG = MainActivity.class.getName();
private ApplicationsAdapter applicationsAdapter;
private void getAppList(){
//get apps asynch
createList(list);
}
private void createList(ArrayList<ApplicationItem> list){
applicationsAdapter = new ApplicationsAdapter(this, R.layout.application_list_item, list);
setListAdapter(applicationsAdapter);
getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
getListView().setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() {
private int nr = 0;
#Override
public boolean onCreateActionMode(android.view.ActionMode mode, Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.cabselection_menu, menu);
return true;
}
#Override
public boolean onPrepareActionMode(android.view.ActionMode mode, Menu menu) {
return false;
}
#Override
public boolean onActionItemClicked(android.view.ActionMode mode, MenuItem item) {
return false;
}
#Override
public void onDestroyActionMode(android.view.ActionMode mode) {
nr = 0;
applicationsAdapter.clearSelection();
}
#Override
public void onItemCheckedStateChanged(android.view.ActionMode mode, int position, long id, boolean checked) {
if (checked) {
nr++;
applicationsAdapter.setNewSelection(position, checked);
L.d(TAG, applicationsAdapter.getItem(position).getAppName());
} else {
nr--;
applicationsAdapter.removeSelection(position);
}
mode.setTitle(nr + " rows selected!");
}
});
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getAppList();
}
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
ApplicationItem item = (ApplicationItem)l.getAdapter().getItem(position);
L.d(TAG + "onListItemClick", applicationsAdapter.getItem(position).getAppName());
l.setItemChecked(position, !applicationsAdapter.isPositionChecked(position));
}
}
In my case, normally this whole thing is inside a fragment, inside the viewpager. For the sake of clarity I changed this into typical activity.
Now, the adapter:
public class ApplicationsAdapter extends ArrayAdapter<ApplicationItem> {
// private HashMap<ApplicationItem, Boolean> objects;
private HashMap<Integer, Boolean> mSelection = new HashMap<Integer, Boolean>();
public ApplicationsAdapter(Context context, int textViewResourceId, ArrayList<ApplicationItem> objects) {
super(context, textViewResourceId, objects);
//this.objects = 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();
}
public ApplicationItem getItem(int position){
return super.getItem(position);
}
public View getView(int position, View convertView, ViewGroup parent){
View v = convertView;
if (v == null) {
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(R.layout.application_list_item, null);
}
ApplicationItem item = super.getItem(position);
if(item != null){
TextView appName = (TextView) v.findViewById(R.id.appName);
TextView appPackage = (TextView) v.findViewById(R.id.appPackage);
ImageView appIcon = (ImageView) v.findViewById(R.id.appIcon);
if (appName != null){
appName.setText(item.getAppName());
}
if (appPackage != null){
appPackage.setText(item.getPackageName());
}
if (appIcon != null){
appIcon.setImageDrawable(item.getIcon());
}
}
v.setBackgroundColor(Color.parseColor("#00FFFFFF")); //default color
if (mSelection.get(position) != null) {
v.setBackgroundColor(Color.BLUE);// this is a selected position so make it red
}
return v;
}
}
THE PROBLEM:
ActionMode is nice, however I'm not sure how to keep selected elements after it's destroy.
Normally inside onDestroyActionMode I'm clearing the selection. Great, so I'll just delete that. Now after clicking the "tick" symbol all apps are still selected. However, getting back to them is now problematic, because ActionMode will only "fire up" when clicking on unselected element.
So - how should I handle that?
Ha, the answer was quite simple. I should have thought about it yesterday, but apparently I was a bit too exhausted.
First of all, I changed the mode of listview into
getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
And deleted setMultiChoiceModeListener() and I'm only using
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
ApplicationItem item = (ApplicationItem)l.getAdapter().getItem(position);
L.d(TAG + "onListItemClick", applicationsAdapter.getItem(position).getAppName());
boolean checked = item.isSelected();
if (!checked) {
item.setSelected(true);
applicationsAdapter.setNewSelection(position, checked);
L.d(TAG, applicationsAdapter.getItem(position).getAppName());
} else {
item.setSelected(false);
applicationsAdapter.removeSelection(position);
}
}
That simple.
Apparently, ActionMode may be fun, but it wasn't the right tool for this job.
And also - adapter from first post can be used as a example of multiselect listView that changes backgrounds instead of checkboxes. Apparently I couldn't find anything simple enough like that.
I have registration form and it has two edittexts and one spinner with adapter for gender selection and value from array, when I click register button and select a gender it's going successfully, but when I don't select a gender and click register button it get force close ?
here is my complete code ....
MainActivity
EditText Fullname, Email;
Spinner GenderSpinner;
Button btnReg;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Importing all assets like buttons, text fields
Fullname = (EditText) findViewById(R.id.full_name);
Email = (EditText) findViewById(R.id.Email);
// Gender = (EditText) findViewById(R.id.Gender);
GenderSpinner = (Spinner) findViewById(R.id.Gender);
ArrayAdapter<CharSequence> GenderAdapter = ArrayAdapter
.createFromResource(this, R.array.sex,
android.R.layout.simple_spinner_item);
GenderAdapter
.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
GenderSpinner.setPrompt("SELECT YOUR GENDER");
GenderSpinner.setAdapter(new NothingSelectedSpinnerAdapter(
GenderAdapter, R.layout.gender_nothing_selected, MainActivity.this));
btnReg = (Button) findViewById(R.id.btnReg);
btnReg.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
// Read EditText dat
String fullname = Fullname.getText().toString();
String email = Email.getText().toString();
String gender = GenderSpinner.getSelectedItem().toString();
}
});
}
}
NothingSelectedSpinnerAdapter
protected static final int EXTRA = 1;
protected SpinnerAdapter adapter;
protected Context context;
protected int nothingSelectedLayout;
protected int nothingSelectedDropdownLayout;
protected LayoutInflater layoutInflater;
public NothingSelectedSpinnerAdapter(SpinnerAdapter spinnerAdapter,
int nothingSelectedLayout, Context context) {
this(spinnerAdapter, nothingSelectedLayout, -1, context);
}
public NothingSelectedSpinnerAdapter(SpinnerAdapter spinnerAdapter,
int nothingSelectedLayout, int nothingSelectedDropdownLayout,
Context context) {
this.adapter = spinnerAdapter;
this.context = context;
this.nothingSelectedLayout = nothingSelectedLayout;
this.nothingSelectedDropdownLayout = nothingSelectedDropdownLayout;
layoutInflater = LayoutInflater.from(context);
}
#Override
public final View getView(int position, View convertView, ViewGroup parent) {
if (position == 0) {
return getNothingSelectedView(parent);
}
return adapter.getView(position - EXTRA, null, parent);
}
protected View getNothingSelectedView(ViewGroup parent) {
return layoutInflater.inflate(nothingSelectedLayout, parent, false);
}
#Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
// BUG! Vote to fix!!
// http://code.google.com/p/android/issues/detail?id=17128 - Spinner
// does not support multiple view types
if (position == 0) {
return nothingSelectedDropdownLayout == -1 ? new View(context)
: getNothingSelectedDropdownView(parent);
}
return adapter.getDropDownView(position - EXTRA, null, parent); // could
}
protected View getNothingSelectedDropdownView(ViewGroup parent) {
return layoutInflater.inflate(nothingSelectedDropdownLayout, parent,
false);
}
#Override
public int getCount() {
int count = adapter.getCount();
return count == 0 ? 0 : count + EXTRA;
}
#Override
public Object getItem(int position) {
return position == 0 ? null : adapter.getItem(position - EXTRA);
}
#Override
public int getItemViewType(int position) {
return position == 0 ? getViewTypeCount() - EXTRA : adapter
.getItemViewType(position - EXTRA);
}
#Override
public int getViewTypeCount() {
return adapter.getViewTypeCount() + EXTRA;
}
#Override
public long getItemId(int position) {
return adapter.getItemId(position - EXTRA);
}
#Override
public boolean hasStableIds() {
return adapter.hasStableIds();
}
#Override
public boolean isEmpty() {
return adapter.isEmpty();
}
#Override
public void registerDataSetObserver(DataSetObserver observer) {
adapter.registerDataSetObserver(observer);
}
#Override
public void unregisterDataSetObserver(DataSetObserver observer) {
adapter.unregisterDataSetObserver(observer);
}
#Override
public boolean areAllItemsEnabled() {
return false;
}
#Override
public boolean isEnabled(int position) {
return position == 0 ? false : true; // don't allow the 'nothing
}
}
It looks like you are getting null here
String gender = GenderSpinner.getSelectedItem().toString();
because nothing has been selected so GenderSpinner.geSelecetedItem() is null when you try to call toString() on it. You could set a selected item as the default item or if you want to force the user to choose an item then you can just check for null here when running this code and if it is then display a message to the user to choose a gender.
If you go with the second option then you may consider using RadioButtons as it will be more natural for the user or use a text hint as the default value of the Spinner with a message of something like "Please choose a gender"
I have a Spinner on my Activity. I use an ArrayList and a custom SpinnerAdapter to populate the list that pops up when the Spinner is pressed.
My problem is the way the Spinner looks on the Activity when it is not pressed. It is all gray. No text is visible. Even after I press the spinner and then choose an item from the resulting list, the Spinner does not populate with text.
Also, when I select an item from the Spinner and then print the selected item position, it prints -1. Many have commented that there is no list of data attached to my spinner, but there obviously is. How else could I press on the Spinner and then choose from a resulting list?
// This sets up the adapter and the arraylist that contains the data
private void setUpAdapter() {
mData = new ArrayList<MyData>();
mAdapter = new MyAdapter(mData);
mSpinner.setAdapter(mAdapter);
mSpinner.setOnItemSelectedListener(new Spinner.OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent,
View view, int pos, long id) {
MyData g = (MyData) parent.getItemAtPosition(pos);
// TODO
}
public void onNothingSelected(AdapterView parent) {
// Do nothing.
}
});
}
// this populates the arraylist that is attached to the spinner's adapter
// it is called once an AsyncTask finishes pulling data from a local database
private void populateSpinner(ArrayList<MyData> result) {
if (result != null) {
if (mData == null) {
mData = new ArrayList<MyData>();
}
else {
mData.clear();
}
for (int index = 0; index < result.size(); index++) {
mData.add(result.get(index));
}
mSpinner.setSelected(0);
}
}
// this is the adapter for the spinner
private class MyAdapter implements SpinnerAdapter {
ArrayList<MyData> data;
public MyAdapter(ArrayList<MyData> data){
this.data = data;
}
#Override
public int getCount() {
return data.size();
}
#Override
public Object getItem(int position) {
return data.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getItemViewType(int position) {
return android.R.layout.simple_spinner_dropdown_item;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView v = new TextView(getApplicationContext());
v.setTextColor(Color.BLACK);
v.setText(data.get(position).getName());
v.setPadding(0, 20, 0, 20);
return v;
}
#Override
public int getViewTypeCount() {
return 1;
}
#Override
public boolean hasStableIds() {
return false;
}
#Override
public boolean isEmpty() {
return false;
}
#Override
public void registerDataSetObserver(DataSetObserver observer) {
// TODO Auto-generated method stub
}
#Override
public void unregisterDataSetObserver(DataSetObserver observer) {
// TODO Auto-generated method stub
}
#Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
return this.getView(position, convertView, parent);
}
}
<Spinner
android:id="#+id/my_spinner"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
When I select an item from the Spinner and then print the selected item position, it prints -1
This is because you are referencing BLANK list
mData = new ArrayList<MyData>();
mAdapter = new MyAdapter(mData);
mSpinner.setAdapter(mAdapter);
Set spinner adapter in onPostExecute() of AsynTask.
#Override
protected void onPreExecute() {
mData = new ArrayList<MyData>();
super.onPreExecute();
}
#Override
protected Void doInBackground(String... params) {
//gets "result" to fill mData
return null;
}
#Override
protected void onPostExecute(Void result) {
setUpAdapter();
}
private void setUpAdapter() {
if (result != null) {
if (mData == null) {
mData = new ArrayList<MyData>();
}
else {
mData.clear();
}
for (int index = 0; index < result.size(); index++) {
mData.add(result.get(index));
}
mAdapter = new MyAdapter(mData);
mSpinner.setAdapter(mAdapter);
mSpinner.setSelected(0);
mSpinner.setOnItemSelectedListener(new Spinner.OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent,
View view, int pos, long id) {
MyData g = (MyData) parent.getItemAtPosition(pos);
// TODO
}
public void onNothingSelected(AdapterView parent) {
// Do nothing.
}
});
}
Use Activity context instead of the Application context for your spinner. See documentation of getApplicationContext() api to understand its proper usage.
Pass the activity context to MyAdapter and use it in creating the TextView's in getView callback.
mAdapter = new MyAdapter(mData, this); // this is activity context.
In MyAdapter :
public MyAdapter(ArrayList<MyData> data, Context context){
this.data = data;
mContext = context;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView v = new TextView(mContext);
v.setTextColor(Color.BLACK);
v.setBackgroundColor(Color.WHITE);
v.setText(data.get(position).getName());
v.setPadding(0, 20, 0, 20);
return v;
}
You can set static sizes using the xml attribute android:layout_height.
Using dp unit instead of px is recommended for multiple screen compatibility.
As for the text, try to use android:prompt attribute in your Spinner xml. For the color I'm guessing it's like other widgets, just use android:textColor
THIS code is WORKING, the spinner correctly display the field, however i must say maybe it is not 100% perfect, cause for some reason im unable to leave blank the initial value of the field, it has by default the value of item 0.
package com.cccheck;
public class OneCheckActivity extends Activity {
LayoutInflater factory;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.spinner_view);
ArrayList tdata = new ArrayList<MyData>();
MyData mdata =new MyData();
mdata.setName("");
mdata.setData("-1");
MyData ndata =new MyData();
ndata.setName("ciao belluzzo");
ndata.setData("1");
tdata.add(mdata);
tdata.add(ndata);
mdata= new MyData();
mdata.setName("vai alla fnac");
mdata.setData("2");
tdata.add(mdata);
mSpinner = (Spinner) findViewById(R.id.my_spinner);
factory = LayoutInflater.from(this);
populateSpinner(tdata);
setUpAdapter();
mSpinner.setSelected(false);
try {
mAdapter.notify();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//mAdapter.registerDataSetObserver(new MyObserver());
}
ArrayList<MyData> mData;
MyAdapter mAdapter = new MyAdapter(null);
Spinner mSpinner;
// This sets up the adapter and the arraylist that contains the data
private void setUpAdapter() {
mSpinner.setOnItemSelectedListener(new Spinner.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent,
View view, int pos, long id) {
MyData g = (MyData) parent.getItemAtPosition(pos);
// TODO
Toast.makeText(OneCheckActivity.this , "selected item : " + pos + ", value: " + g.getData(),Toast.LENGTH_LONG).show();
}
#Override
public void onNothingSelected(AdapterView parent) {
// Do nothing.
}
});
}
// this populates the arraylist that is attached to the spinner's adapter
//it is called once an AsyncTask finishes pulling data from a local database
private void populateSpinner(ArrayList<MyData> result) {
if (result != null) {
if (mData == null) {
mData = new ArrayList<MyData>();
}
else {
mData.clear();
}
for (int index = 0; index < result.size(); index++) {
mData.add(result.get(index));
}
mAdapter = new MyAdapter(mData);
mSpinner.setAdapter(mAdapter);
}
}
// this is the adapter for the spinner
private class MyAdapter implements SpinnerAdapter {
ArrayList<MyData> data;
public MyAdapter(ArrayList<MyData> data){
this.data = data;
}
public void updateData(ArrayList<MyData> data){
this.data = data;
}
#Override
public int getCount() {
return data.size();
}
#Override
public Object getItem(int position) {
return data.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getItemViewType(int position) {
return android.R.layout.simple_spinner_dropdown_item;
}
#Override
public LinearLayout getView(int position, View convertView, ViewGroup parent) {
LinearLayout pv = (LinearLayout)(factory.inflate(R.layout.spinner_item, null));
TextView tv = (TextView) pv.findViewById(R.id.textviewid);
tv.setTextColor(Color.BLACK);
MyData item = data.get(position);
tv.setText( item.getName() + " - " + item.getData() + " ");
tv.setPadding(0, 20, 0, 20);
return pv;
}
#Override
public int getViewTypeCount() {
return 1;
}
#Override
public boolean hasStableIds() {
return false;
}
#Override
public boolean isEmpty() {
return data.isEmpty();
}
#Override
public void registerDataSetObserver(DataSetObserver observer) {
// TODO Auto-generated method stub
}
#Override
public void unregisterDataSetObserver(DataSetObserver observer) {
// TODO Auto-generated method stub
}
#Override
public LinearLayout getDropDownView(int position, View convertView, ViewGroup parent) {
if (convertView instanceof LinearLayout) System.out.println("%%%%%%%%%%%%%%55555 hai ragione");
return this.getView(position, convertView, parent);
}
}
}
use this as layout for spinner_item.xml
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textSize="28px"
android:id="#+id/textviewid"
/>
</LinearLayout>
I would like the spinner dropdown to open right below the spinner itself.
E.g.:
How can i set the position of spinner dropdown?
Declare the spinner mode as a dropdown:
android:spinnerMode="dropdown"
then use the vertical offset to close the gap:
android:dropDownVerticalOffset="-15dp"
Spinner Android Documentation
You have to extend Spinner and change the location of AlertDialog (spinner when clicked acts as alertDialog).
Code (does a bit more than just position, it also sets background for opened spinner):
public class CustomSpinner extends Spinner {
private AlertDialog mPopup;
public CustomSpinner(Context context) {
super(context);
}
public CustomSpinner(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomSpinner(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
}
#Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (mPopup != null && mPopup.isShowing()) {
mPopup.dismiss();
mPopup = null;
}
}
//when clicked alertDialog is made
#Override
public boolean performClick() {
Context context = getContext();
AlertDialog.Builder builder = new AlertDialog.Builder(context);
CharSequence prompt = getPrompt();
if (prompt != null) {
builder.setTitle(prompt);
}
mPopup = builder.setSingleChoiceItems(
new DropDownAdapter(getAdapter()),
getSelectedItemPosition(), this).show();
WindowManager.LayoutParams WMLP = mPopup.getWindow().getAttributes();
//width and height must be set to anything other than WRAP_CONTENT!
WMLP.x = 0; // x position
WMLP.y = 50; // y position
WMLP.height =390 ; //LayoutParams.WRAP_CONTEN
WMLP.width = 315;
WMLP.horizontalMargin = 0;
WMLP.verticalMargin = 0;
mPopup.getWindow().setAttributes(WMLP);
//ListView.getDefaultSize(size, measureSpec)
ListView listView = mPopup.getListView();
//listView.set
// Remove divider between rows
listView.setDivider(null);
// Set custom background
listView.setBackgroundResource(R.drawable.drop);
// Remove background from all (grand)parent's
ViewParent parent = listView.getParent();
while (parent != null && parent instanceof View) {
((View) parent).setBackgroundDrawable(null);
parent = parent.getParent();
}
return true;
}
#Override
public void onClick(DialogInterface dialog, int which) {
setSelection(which);
dialog.dismiss();
mPopup = null;
}
* <p>Wrapper class for an Adapter. Transforms the embedded Adapter instance
* into a ListAdapter.</p>
*/
private static class DropDownAdapter implements ListAdapter, SpinnerAdapter {
private SpinnerAdapter mAdapter;
/**
* <p>Creates a new ListAddapter wrapper for the specified adapter.</p>
*
* #param adapter the Adapter to transform into a ListAdapter
*/
public DropDownAdapter(SpinnerAdapter adapter) {
this.mAdapter = adapter;
}
public int getCount() {
return mAdapter == null ? 0 : mAdapter.getCount();
}
public Object getItem(int position) {
return mAdapter == null ? null : mAdapter.getItem(position);
}
public long getItemId(int position) {
return mAdapter == null ? -1 : mAdapter.getItemId(position);
}
public View getView(int position, View convertView, ViewGroup parent) {
return getDropDownView(position, convertView, parent);
}
public View getDropDownView(int position, View convertView, ViewGroup parent) {
return mAdapter == null ? null :
mAdapter.getDropDownView(position, convertView, parent);
}
public boolean hasStableIds() {
return mAdapter != null && mAdapter.hasStableIds();
}
public void registerDataSetObserver(DataSetObserver observer) {
if (mAdapter != null) {
mAdapter.registerDataSetObserver(observer);
}
}
public void unregisterDataSetObserver(DataSetObserver observer) {
if (mAdapter != null) {
mAdapter.unregisterDataSetObserver(observer);
}
}
/**
* <p>Always returns false.</p>
*
* #return false
*/
public boolean areAllItemsEnabled() {
return true;
}
/**
* <p>Always returns false.</p>
*
* #return false
*/
public boolean isEnabled(int position) {
return true;
}
public int getItemViewType(int position) {
return 0;
}
public int getViewTypeCount() {
return 1;
}
public boolean isEmpty() {
return getCount() == 0;
}
}
}
Then you just gotta insert it to your layout with "yourPackage.CustomSpinner" element like:
<yourPackage.CustomSpinner
android:layout_height="wrap_content"
android:id="#+id/spinner"
android:layout_width="fill_parent">
</yourPackage.CustomSpinner>
For dropdown Spinner mode you can use this:
mSortingSpinner.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
mSortingSpinner.setDropDownVerticalOffset(
mSortingSpinner.getDropDownVerticalOffset() + mSortingSpinner.getHeight());
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
mSortingSpinner.getViewTreeObserver().removeOnGlobalLayoutListener(this);
} else {
mSortingSpinner.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
}
});
This set vertical offset of dropdown by spinner height.