Comment définir la valeur par défaut de Spinner sur null?

J’essaie de charger un Spinner sans valeur sélectionnée. Une fois que l’utilisateur sélectionne une valeur, il les emmène ensuite sur une autre page.

Cela pose problème car, à l’heure actuelle, la page se charge tout simplement avant que l’utilisateur ait le choix de choisir.

Mon cours de spinner est configuré de la même manière que celui de Google: http://developer.android.com/resources/tutorials/views/hello-spinner.html

Donc, fondamentalement, est-il possible d’avoir un spinner qui se charge avec rien de sélectionné car actuellement, il charge le premier élément de mon tableau de chaînes.

est-il possible d’avoir un spinner qui charge avec rien sélectionné

Seulement s’il n’y a pas de données. Si vous avez 1+ éléments dans SpinnerAdapter , le Spinner aura toujours une sélection.

Spinners ne sont pas conçus pour être des widgets de commande. Les utilisateurs ne s’attendent pas à ce qu’une sélection dans un Spinner démarre une activité. S’il vous plaît envisager d’utiliser quelque chose d’autre, comme un ListView ou GridView , au lieu d’un Spinner .


MODIFIER

BTW, j’ai oublié de mentionner – vous pouvez toujours mettre une entrée supplémentaire dans votre adaptateur qui représente “pas de sélection”, et en faire l’élément initial sélectionné dans le Spinner .

Vous pouvez également remplacer votre adaptateur spinner et fournir une vue vide pour la position 0 dans votre méthode getView et une vue avec une hauteur 0dp dans la méthode getDropDownView .

De cette façon, vous avez un texte initial tel que “Sélectionner une option …” qui apparaît lorsque le premier disque est chargé, mais ce n’est pas une option que l’utilisateur peut choisir (techniquement, mais parce que la hauteur est 0). , ils ne peuvent pas le voir).

Ceci est une implémentation complète de l’idée de Paul Bourdeaux , à savoir renvoyer une vue initiale spéciale (ou une vue vide) dans getView() pour la position 0.

Cela fonctionne pour moi et est relativement simple. Vous pourriez envisager cette approche surtout si vous avez déjà un adaptateur personnalisé pour votre Spinner. (Dans mon cas, j’utilisais un adaptateur personnalisé afin de personnaliser facilement la mise en page des éléments, chaque élément comportant deux vues TextViews.)

L’adaptateur serait quelque chose dans ce sens:

 public class MySpinnerAdapter extends ArrayAdapter { public MySpinnerAdapter(Context context, List items) { super(context, R.layout.my_spinner_row, items); } @Override public View getDropDownView(int position, View convertView, @NonNull ViewGroup parent) { if (position == 0) { return initialSelection(true); } return getCustomView(position, convertView, parent); } @NonNull @Override public View getView(int position, View convertView, @NonNull ViewGroup parent) { if (position == 0) { return initialSelection(false); } return getCustomView(position, convertView, parent); } @Override public int getCount() { return super.getCount() + 1; // Adjust for initial selection item } private View initialSelection(boolean dropdown) { // Just an example using a simple TextView. Create whatever default view // to suit your needs, inflating a separate layout if it's cleaner. TextView view = new TextView(getContext()); view.setText(R.ssortingng.select_one); int spacing = getContext().getResources().getDimensionPixelSize(R.dimen.spacing_smaller); view.setPadding(0, spacing, 0, spacing); if (dropdown) { // Hidden when the dropdown is opened view.setHeight(0); } return view; } private View getCustomView(int position, View convertView, ViewGroup parent) { // Distinguish "real" spinner items (that can be reused) from initial selection item View row = convertView != null && !(convertView instanceof TextView) ? convertView : LayoutInflater.from(getContext()).inflate(R.layout.my_spinner_row, parent, false); position = position - 1; // Adjust for initial selection item MyModel item = getItem(position); // ... Resolve views & populate with data ... return row; } } 

C’est tout. Notez que si vous utilisez un OnItemSelectedListener avec votre Spinner, dans onItemSelected() vous devrez également ajuster la position pour prendre en compte l’élément par défaut, par exemple:

 if (position == 0) { return; } else { position = position - 1; } MyModel selected = items.get(position); 

Dans mon cas, bien que la taille “2” soit affichée dans le spinner, rien ne se passe avant qu’une sélection soit faite!

J’ai un fichier xml (data_sizes.xml) qui répertorie toutes les valeurs de spinner.

    2 4 8 16 32   

Dans le fichier main.xml: Élément Spinner

  

Ensuite, dans mon code Java, j’ai ajouté:

Dans mon activité: Déclaration

 Spinner spinnerSize; ArrayAdapter adapter; 

Dans une fonction void publique – initControls (): Définition

 spinnerSize = (Spinner)findViewById(R.id.spinnerSize); adapter = ArrayAdapter.createFromResource(this, R.array.chunks, android.R.layout.simple_spinner_item); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spinnerSize.setAdapter(adapter); spinnerSize.setOnItemSelectedListener(new MyOnItemSelectedListener()); 

Mon écouteur:

/ * Spinner Listener * /

 class MyOnItemSelectedListener implements OnItemSelectedListener { public void onItemSelected(AdapterView parent, View view, int pos, long id) { chunkSize = new Integer(parent.getItemAtPosition(pos).toSsortingng()).intValue(); } public void onNothingSelected(AdapterView parent) { // Dummy } } 

En utilisant une mise en page personnalisée comme celle-ci:

   

Dans l’activité:

  // populate the list ArrayList dataList = new ArrayList(); for (int i = 0; i < 4; i++) { dataList.add("Item"); } // set custom layout spinner_layout.xml and adapter Spinner spinnerObject = (Spinner) findViewById(R.id.spinnerObject); ArrayAdapter dataAdapter = new ArrayAdapter(this, R.drawable.spinner_layout, dataList); dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spinnerObject.setAdapter(dataAdapter); spinnerObject.setOnTouchListener(new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { // to set value of first selection, because setOnItemSelectedListener will not dispatch if the user selects first element TextView spinnerTarget = (TextView)v.findViewById(R.id.spinnerTarget); spinnerTarget.setText(spinnerObject.getSelectedItem().toSsortingng()); return false; } }); spinnerObject.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { private boolean selectionControl = true; public void onItemSelected(AdapterView parent, View view, int pos, long id) { // just the first time if(selectionControl){ // find TextView in layout TextView spinnerTarget = (TextView)parent.findViewById(R.id.spinnerTarget); // set spinner text empty spinnerTarget.setText(""); selectionControl = false; } else{ // select object } } public void onNothingSelected(AdapterView parent) { } }); 

Fusionner ceci:

 private long previousItemId = 0; @Override public long getItemId(int position) { long nextItemId = random.nextInt(Integer.MAX_VALUE); while(previousItemId == nextItemId) { nextItemId = random.nextInt(Integer.MAX_VALUE); } previousItemId = nextItemId; return nextItemId; } 

Avec cette réponse :

 public class SpinnerInteractionListener implements AdapterView.OnItemSelectedListener, View.OnTouchListener { private AdapterView.OnItemSelectedListener onItemSelectedListener; public SpinnerInteractionListener(AdapterView.OnItemSelectedListener selectedListener) { this.onItemSelectedListener = selectedListener; } boolean userSelect = false; @Override public boolean onTouch(View v, MotionEvent event) { userSelect = true; return false; } @Override public void onItemSelected(AdapterView parent, View view, int pos, long id) { if(userSelect) { onItemSelectedListener.onItemSelected(parent, view, pos, id); userSelect = false; } } @Override public void onNothingSelected(AdapterView parent) { if(userSelect) { onItemSelectedListener.onNothingSelected(parent); userSelect = false; } } } 

vous pouvez mettre la première cellule de votre tableau vide ({“”, “some”, “some”, …}) et ne rien faire si la position est 0;

 public void onItemSelected(AdapterView parent, View view, int position, long id) { if(position>0) { label.setText(MainActivity.questions[position - 1]); } } 
  • Si vous remplissez le tableau par fichier XML, vous pouvez laisser le premier élément vide

Ma solution, si vous avez un TextView comme chaque ligne du spinner:

  // TODO: add a fake item as the last one of "items" final ArrayAdapter adapter=new ArrayAdapter(..,..,items) { @Override public View getDropDownView(final int position,final View convertView,final ViewGroup parent) { final View dropDownView=super.getDropDownView(position,convertView,parent); ((TextView)dropDownView.findViewById(android.R.id.text1)).setHeight(position==getCount()-1?0:getDimensionFromAtsortingbute(..,R.attr.dropdownListPreferredItemHeight)); dropDownView.getLayoutParams().height=position==getCount()-1?0:LayoutParams.MATCH_PARENT; return dropDownView; } } ... spinner.setAdapter(adapter); _actionModeSpinnerView.setSelection(dataAdapter.getCount()-1,false); public static int getDimensionFromAtsortingbute(final Context context,final int attr) { final TypedValue typedValue=new TypedValue(); if(context.getTheme().resolveAtsortingbute(attr,typedValue,true)) return TypedValue.complexToDimensionPixelSize(typedValue.data,context.getResources().getDisplayMesortingcs()); return 0; } 

Base sur la réponse @Jonik J’ai créé une extension entièrement fonctionnelle pour ArrayAdapter

 class SpinnerArrayAdapter : ArrayAdapter { private val selectText : Ssortingng private val resource: Int private val fieldId : Int private val inflater : LayoutInflater constructor(context: Context?, resource: Int, objects: Array, selectText : Ssortingng? = null) : super(context, resource, objects) { this.selectText = selectText ?: context?.getSsortingng(R.ssortingng.spinner_default_select_text) ?: "" this.resource = resource this.fieldId = 0 this.inflater = LayoutInflater.from(context) } constructor(context: Context?, resource : Int, objects: List, selectText : Ssortingng? = null) : super(context, resource, objects) { this.selectText = selectText ?: context?.getSsortingng(R.ssortingng.spinner_default_select_text) ?: "" this.resource = resource this.fieldId = 0 this.inflater = LayoutInflater.from(context) } constructor(context: Context?, resource: Int, textViewResourceId: Int, objects: Array, selectText : Ssortingng? = null) : super(context, resource, textViewResourceId, objects) { this.selectText = selectText ?: context?.getSsortingng(R.ssortingng.spinner_default_select_text) ?: "" this.resource = resource this.fieldId = textViewResourceId this.inflater = LayoutInflater.from(context) } constructor(context: Context?, resource : Int, textViewResourceId: Int, objects: List, selectText : Ssortingng? = null) : super(context, resource, textViewResourceId, objects) { this.selectText = selectText ?: context?.getSsortingng(R.ssortingng.spinner_default_select_text) ?: "" this.resource = resource this.fieldId = textViewResourceId this.inflater = LayoutInflater.from(context) } override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup?): View { if(position == 0) { return initialSelection(true) } return createViewFromResource(inflater, position -1, convertView, parent, resource) } override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { if(position == 0) { return initialSelection(false) } return createViewFromResource(inflater, position -1, convertView, parent, resource) } override fun getCount(): Int { return super.getCount() + 1 // adjust for initial selection } private fun initialSelection(inDropDown: Boolean) : View { // Just simple TextView as initial selection. val view = TextView(context) view.setText(selectText) view.setPadding(8, 0, 8, 0) if(inDropDown) { // Hide when dropdown is open view.height = 0 } return view } private fun createViewFromResource(inflater: LayoutInflater, position: Int, @Nullable convertView: View?, parent: ViewGroup?, resource: Int): View { val view: View val text: TextView? if (convertView == null || (convertView is TextView)) { view = inflater.inflate(resource, parent, false) } else { view = convertView } try { if (fieldId === 0) { // If no custom field is assigned, assume the whole resource is a TextView text = view as TextView } else { // Otherwise, find the TextView field within the layout text = view.findViewById(fieldId) if (text == null) { throw RuntimeException("Failed to find view with ID " + context.getResources().getResourceName(fieldId) + " in item layout") } } } catch (e: ClassCastException) { Log.e("ArrayAdapter", "You must supply a resource ID for a TextView") throw IllegalStateException( "ArrayAdapter requires the resource ID to be a TextView", e) } val item = getItem(position) if (item is CharSequence) { text.text = item } else { text.text = item!!.toSsortingng() } return view }