web-dev-qa-db-fra.com

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 dirige vers une autre page. 

Cela s'avère être un problème car à l'heure actuelle, la page se charge tout de suite avant que l'utilisateur n'ait le choix.

Ma classe spinner est configurée de la même manière que celle de Google: http://developer.Android.com/resources/tutorials/views/hello-spinner.html

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

49
Oli

est-il possible d'avoir une roulette qui charge avec rien sélectionné

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

Spinners ne sont pas conçus pour être des widgets de commande. Les utilisateurs ne s'attendent pas à une sélection dans une Spinner pour démarrer une activité. Pensez à utiliser quelque chose d'autre, tel que ListView ou GridView, au lieu de Spinner.


MODIFIER

Au fait, j'ai oublié de le mentionner - vous pouvez toujours insérer dans votre adaptateur une entrée supplémentaire qui représente "aucune sélection" et en faire l'élément sélectionné initialement dans la Spinner.

76
CommonsWare

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 de 0dp dans la méthode getDropDownView.

De cette façon, vous avez un texte initial tel que "Sélectionnez une option ..." qui apparaît lorsque le compteur est chargé pour la première fois, mais ce n'est pas une option à choisir pour l'utilisateur , ils ne peuvent pas le voir).

27
Paul Bourdeaux

Il s'agit d'une implémentation complète de idée de Paul Bourdeaux , à savoir le retour d'une vue initiale spéciale (ou une vue vide) dans getView() pour la position 0.

Cela fonctionne pour moi et est relativement simple. Vous pouvez envisager cette approche en particulier si vous avez déjà un adaptateur personnalisé pour votre Spinner. (Dans mon cas, j’utilisais un adaptateur personnalisé pour personnaliser facilement la disposition des éléments, chaque élément ayant quelques TextViews.)

L'adaptateur serait quelque chose du genre:

public class MySpinnerAdapter extends ArrayAdapter<MyModel> {

    public MySpinnerAdapter(Context context, List<MyModel> 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.string.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 une OnItemSelectedListener avec votre spinner, dans onItemSelected(), vous devrez également ajuster 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);
17
Jonik

Dans mon cas, bien que la taille '2' soit affichée dans la roulette, rien ne se passe tant que la sélection n’est pas faite!

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

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string-array name="chunks">
        <item>2</item>
        <item>4</item>
        <item>8</item>
        <item>16</item>
        <item>32</item>
    </string-array>
</resources>    

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

<Spinner Android:id="@+id/spinnerSize"  
Android:layout_marginLeft="50px"
Android:layout_width="fill_parent"                  
Android:drawSelectorOnTop="true"
Android:layout_marginTop="5dip"
Android:Prompt="@string/SelectSize"
Android:layout_marginRight="30px"
Android:layout_height="35px" /> 

Puis dans mon code Java, j'ai ajouté:

Dans mon activité: déclaration

Spinner spinnerSize;
ArrayAdapter adapter;

Dans une fonction vide publique - initControls (): Definition

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 auditeur spinner:

/ * Spinner Listener * /

class MyOnItemSelectedListener implements OnItemSelectedListener {

    public void onItemSelected(AdapterView<?> parent,
        View view, int pos, long id) {
        chunkSize = new Integer(parent.getItemAtPosition(pos).toString()).intValue();
    }
    public void onNothingSelected(AdapterView<?> parent) {
      // Dummy
    }
}
5
TheCottonSilk

Utiliser une disposition spinner personnalisée comme ceci: 

<?xml version="1.0" encoding="utf-8"?>
<Spinner xmlns:Android="http://schemas.Android.com/apk/res/Android"
          Android:id="@+id/spinnerTarget"
          Android:layout_width="fill_parent"
          Android:layout_height="wrap_content"
          Android:textSize="14dp"         
          Android:textColor="#000000"/>

Dans l'activité:

    // populate the list
    ArrayList<String> dataList = new ArrayList<String>();
    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<String> dataAdapter = new ArrayAdapter<String>(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().toString());

            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) {

                }
            });
3
gts

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 ceci répondre :

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;
        }
    }
}
3
EpicPandaForce

vous pouvez mettre la première cellule de votre tableau vide ({"", "certains", "certains", ...}) 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
1
khaled_alokby

Ma solution, au cas où vous auriez un TextView comme chaque ligne du disque:

    // TODO: add a fake item as the last one of "items"
    final ArrayAdapter<String> adapter=new ArrayAdapter<String>(..,..,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:getDimensionFromAttribute(..,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 getDimensionFromAttribute(final Context context,final int attr)
    {
    final TypedValue typedValue=new TypedValue();
    if(context.getTheme().resolveAttribute(attr,typedValue,true))
      return TypedValue.complexToDimensionPixelSize(typedValue.data,context.getResources().getDisplayMetrics());
    return 0;
    }
1
android developer

Je suppose que vous voulez avoir une Spinner avec le premier élément invisible vide (c'est une caractéristique étrange de Spinner qui ne peut pas afficher une liste sans sélectionner un élément). Vous devriez ajouter une classe qui contiendra des données:

data class YourData(val id: Int, val name: String?)

Ceci est l'adaptateur.

class YourAdapter(
    context: Context,
    private val textViewResourceId: Int,
    private var items: ArrayList<YourData>
) : ArrayAdapter<YourData>(context, textViewResourceId, items) {

    private var inflater: LayoutInflater = context.getSystemService(
        Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater

    override fun getCount(): Int = items.size + 1

    override fun getItem(position: Int): YourData? =
        if (position == 0) YourData(0, "") else items[position - 1]

    override fun getItemId(position: Int): Long = position.toLong()

    override fun getView(position: Int, convertView: View?, parent: ViewGroup): View =
        if (position == 0) {
            getFirstTextView(convertView)
        } else {
            getTextView(convertView, parent, position - 1)
        }

    override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View =
        getView(position, convertView, parent)

    private fun getFirstTextView(convertView: View?): View {
        // Just simple TextView as initial selection.
        var textView: TextView? = convertView as? TextView
        val holder: FirstViewHolder
        if (textView?.tag !is FirstViewHolder) {
            textView = TextView(context) // inflater.inflate(R.layout.your_text, parent, false) as TextView
            textView.height = 0 // Hide first item.
            holder = FirstViewHolder()
            holder.textView = textView
            textView.tag = holder
        }
        return textView
    }

    private fun getTextView(
        convertView: View?,
        parent: ViewGroup,
        position: Int
    ): TextView {
        var textView: TextView? = convertView as? TextView
        val holder: ViewHolder
        if (textView?.tag is ViewHolder) {
            holder = textView.tag as ViewHolder
        } else {
            textView = inflater.inflate(textViewResourceId, parent, false) as TextView
            holder = ViewHolder()
            holder.textView = textView
            textView.tag = holder
        }
        holder.textView.text = items[position].name

        return textView
    }

    private class FirstViewHolder {
        lateinit var textView: TextView
    }

    private class ViewHolder {
        lateinit var textView: TextView
    }
}

Créer: 

YourAdapter(context!!, R.layout.text_item, ArrayList())

Pour ajouter des articles:

private fun fill(items: List<YourData>, adapter: YourAdapter) {
    adapter.run {
        clear()
        addAll(items)
        notifyDataSetChanged()
    }
}

Lorsque vous chargez des éléments dans votre Spinner avec cette commande fill(), vous devez savoir que les index sont également incrémentés. Donc, si vous souhaitez sélectionner le 3ème élément, vous devez maintenant sélectionner le 4ème: spinner?.setSelection(index + 1)

0
CoolMind

Basé sur @Jonik answer, j'ai créé une extension entièrement fonctionnelle pour ArrayAdapter 

class SpinnerArrayAdapter<T> : ArrayAdapter<T> {

    private val selectText : String
    private val resource: Int
    private val fieldId : Int
    private val inflater : LayoutInflater

    constructor(context: Context?, resource: Int, objects: Array<T>, selectText : String? = null) : super(context, resource, objects) {
        this.selectText = selectText ?: context?.getString(R.string.spinner_default_select_text) ?: ""
        this.resource = resource
        this.fieldId = 0
        this.inflater = LayoutInflater.from(context)
    }
    constructor(context: Context?, resource : Int, objects: List<T>, selectText : String? = null) : super(context, resource, objects) {
        this.selectText = selectText ?: context?.getString(R.string.spinner_default_select_text) ?: ""
        this.resource = resource
        this.fieldId = 0
        this.inflater = LayoutInflater.from(context)
    }
    constructor(context: Context?, resource: Int, textViewResourceId: Int, objects: Array<T>, selectText : String? = null) : super(context, resource, textViewResourceId, objects) {
        this.selectText = selectText ?: context?.getString(R.string.spinner_default_select_text) ?: ""
        this.resource = resource
        this.fieldId = textViewResourceId
        this.inflater = LayoutInflater.from(context)
    }
    constructor(context: Context?, resource : Int, textViewResourceId: Int, objects: List<T>, selectText : String? = null) : super(context, resource, textViewResourceId,  objects) {
        this.selectText = selectText ?: context?.getString(R.string.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!!.toString()
        }

        return view
    }
0
Michał Ziobro