wake-up-neo.com

Wie setze ich den Spinner-Standardwert auf null?

Ich versuche, einen Spinner ohne ausgewählten Wert zu laden. Sobald der Benutzer einen Wert ausgewählt hat, führt er sie auf eine andere Seite. 

Dies stellt sich als problematisch dar, da die Seite derzeit gerade geladen wird, bevor der Benutzer die Wahl hat.

Meine Spinner-Klasse ist wie die von Google eingerichtet: http://developer.Android.com/resources/tutorials/views/hello-spinner.html

Im Grunde ist es also möglich, einen Spinner zu laden, der nichts ausgewählt hat, da er derzeit das erste Element in meinem String-Array lädt.

49
Oli

ist es möglich, einen Spinner zu haben, der geladen wird, wenn nichts ausgewählt ist

Nur wenn keine Daten vorhanden sind. Wenn Sie mehr als 1 Elemente in der Variablen SpinnerAdapter haben, hat die Variable Spinner immer eine Auswahl.

Spinners sind nicht als Befehlswidgets gedacht. Benutzer erwarten keine Auswahl in einer Spinner, um eine Aktivität zu starten. Erwägen Sie die Verwendung einer anderen Variable, beispielsweise einer ListView oder GridView, anstelle einer Spinner.


EDIT

Übrigens, ich habe vergessen zu erwähnen - Sie können immer einen zusätzlichen Eintrag in Ihren Adapter einfügen, der "keine Auswahl" darstellt, und ihn zum ersten ausgewählten Element in der Spinner machen.

76
CommonsWare

Alternativ können Sie Ihren Spinner-Adapter überschreiben und eine leere Ansicht für Position 0 in Ihrer getView-Methode und eine Ansicht mit 0dp-Höhe in der getDropDownView-Methode bereitstellen.

Auf diese Weise haben Sie einen Anfangstext wie "Wählen Sie eine Option ...", der angezeigt wird, wenn der Spinner zum ersten Mal geladen wird. Dies ist jedoch keine Option, die der Benutzer auswählen kann (technisch gesehen ist dies der Fall, aber die Höhe ist 0 sie können es nicht sehen).

27
Paul Bourdeaux

Dies ist eine vollständige Implementierung von der Idee von Paul Bourdeaux , nämlich dass für Position 0 eine spezielle erste Ansicht (oder eine leere Ansicht) in getView() zurückgegeben wird.

Es funktioniert für mich und ist relativ unkompliziert. Sie können diesen Ansatz vor allem für in Betracht ziehen, wenn Sie bereits einen benutzerdefinierten Adapter für Ihren Spinner haben. (In meinem Fall habe ich einen benutzerdefinierten Adapter verwendet, um das Layout der Elemente auf einfache Weise anzupassen, wobei jedes Element über ein paar TextViews verfügt.)

Der Adapter wäre in etwa so:

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

}

Das ist es. Wenn Sie eine OnItemSelectedListener mit Ihrem Spinner verwenden, müssen Sie in onItemSelected() auch position anpassen, um das Standardelement zu berücksichtigen. Beispiel:

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

In meinem Fall, obwohl die Größe '2' im Spinner angezeigt wird, passiert nichts, bis eine Auswahl getroffen wurde!

Ich habe eine XML-Datei (data_sizes.xml), die alle Spinnerwerte auflistet.

<?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>    

In der main.xml-Datei: Spinner-Element

<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" /> 

Dann fügte ich in meinem Java-Code hinzu:

In meiner Tätigkeit: Erklärung

Spinner spinnerSize;
ArrayAdapter adapter;

In einer öffentlichen Void-Funktion - 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());

Mein Spinner Zuhörer:

/ * 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

Verwenden Sie ein benutzerdefiniertes Spinner-Layout wie folgt: 

<?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"/>

In der Tätigkeit:

    // 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

Zusammenführen:

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

Mit dieser Antwort :

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

sie können die erste Zelle in Ihrem Array leer setzen ({"", "einige", "einige", ...}).

public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
    if(position>0) {
        label.setText(MainActivity.questions[position - 1]);
    }
}
  • wenn Sie das Array mit einer XML-Datei füllen, können Sie das erste Element leer lassen
1
khaled_alokby

Meine Lösung, falls Sie eine TextView als jede Reihe des Spinners haben:

    // 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

Ich gehe davon aus, dass Sie eine Spinner mit dem ersten leeren unsichtbaren Element haben möchten (dies ist eine seltsame Funktion von Spinner, die keine Liste anzeigen kann, ohne ein Element auszuwählen). Sie sollten eine Klasse hinzufügen, die Daten enthält:

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

Dies ist der Adapter.

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
    }
}

Erschaffen: 

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

Artikel hinzufügen:

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

Wenn Sie Elemente mit diesem fill()-Befehl in Ihren Spinner laden, sollten Sie wissen, dass auch Indizes inkrementiert werden. Wenn Sie also den dritten Punkt auswählen möchten, sollten Sie jetzt den vierten auswählen: spinner?.setSelection(index + 1)

0
CoolMind

Basierend auf @Jonik Antwort Ich habe eine voll funktionsfähige Erweiterung für ArrayAdapter erstellt 

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