Domanda

Sto cercando di ottenere uno Spinner per caricare senza alcun valore selezionato. Una volta che l'utente seleziona un valore che poi li porta ad un'altra pagina.

Questo sta dimostrando di essere un problema, perché allo stato attuale, la pagina appena carichi subito prima che l'utente ottiene una scelta di scegliere.

La mia classe ogiva è impostato allo stesso modo di Google di: http: //developer.android.com/resources/tutorials/views/hello-spinner.html

Quindi, fondamentalmente, è possibile avere uno spinner che carichi con nulla selezionati perché in questo momento, si carica il primo articolo nel mio array di stringhe.

È stato utile?

Soluzione

E 'possibile avere uno spinner che carichi con nulla selezionato

Solo se non ci sono dati. Se si dispone di 1+ elementi nel SpinnerAdapter, il Spinner avrà sempre una selezione.

Spinners non sono progettati per essere i widget di comando. Gli utenti non si aspettano una selezione in un Spinner per avviare un'attività. Si prega di considerare l'utilizzo di qualcosa di diverso, come un ListView o GridView, al posto di un Spinner.


Modifica

A proposito, ho dimenticato di dire - si può sempre mettere una voce in più nel vostro adattatore che rappresenta "nessuna selezione", e ne fanno l'elemento iniziale selezionata nel Spinner

.

Altri suggerimenti

In alternativa, si potrebbe sostituire la scheda di filatore, e fornire una visione vuoto per la posizione 0 nel metodo GetView, e una vista con altezza 0DP nel metodo getDropDownView.

In questo modo, si ha un testo iniziale come "selezionare un'opzione ..." che si presenta quando l'ogiva viene caricato, ma non è un'opzione per l'utente di scegliere (tecnicamente lo è, ma perché il l'altezza è pari a 0, che non possono vederla).

Questa è un'implementazione completa dell'idea di Paul Bourdeaux, cioè restituendo una speciale vista iniziale (o una vista vuoto) in getView() per la posizione 0.

Funziona per me ed è relativamente semplice. Si potrebbe considerare questo approccio particolare se si dispone già di un adattatore personalizzato per la vostra Spinner. (Nel mio caso, stavo usando adattatore personalizzato al fine di personalizzare facilmente il layout degli elementi, ogni elemento avere un paio di TextViews.)

L'adattatore sarebbe qualcosa in queste righe:

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

}

Questo è tutto. Si noti che se si utilizza un OnItemSelectedListener con la Spinner, in onItemSelected() si avrebbe anche per regolare position di prendere l'elemento predefinito in considerazione, ad esempio:

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

Nel mio caso, anche se le dimensioni '2' viene visualizzato nella filatrice, non succede nulla fino a qualche selezione è fatta!

Ho un file XML (data_sizes.xml), che elenca tutti i valori filatore.

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

Nel file di main.xml: elemento 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" /> 

Poi, nel mio codice Java, ho aggiunto:

Nella mia attività: Dichiarazione

Spinner spinnerSize;
ArrayAdapter adapter;

In una funzione public void - initControls (): Definizione

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());

Il mio filatore ascoltatore:

/ * Spinner ascoltatore * /

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

Utilizzando un layout personalizzato filatore in questo modo:

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

Nell'attività:

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

                }
            });

Unisci questo:

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

Con questo risposta :

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

si può mettere la prima cella nella propria matrice essere vuoto ({ "", "alcuni", "alcuni", ...}) e non fare nulla se la posizione è 0;

public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
    if(position>0) {
        label.setText(MainActivity.questions[position - 1]);
    }
}
  • se si compila la matrice da file XML si può lasciare che il primo elemento vuoto

La mia soluzione, nel caso in cui si dispone di una TextView come ogni riga del filatore:

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

Base @ Jonik risposta che ho creato un'estensione completamente funzionale per 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
    }

Presumo che si desidera avere un Spinner con primo elemento invisibile vuoto (che è una caratteristica strana di Spinner che non possono mostrare un elenco senza selezionare una voce). Si dovrebbe aggiungere una classe che conterrà i dati:

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

Questa è l'adattatore.

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

Per creare:

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

Per aggiungere elementi:

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

Quando si carica elementi alla Spinner con quel comando fill(), si dovrebbe sapere, che gli indici sono anche incrementati. Quindi, se si desidera selezionare terzo elemento, si dovrebbe ora selezionare 4: spinner?.setSelection(index + 1)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top