style llenar item android spinner

android - llenar - Crear un setError() para el Spinner



llenar spinner android (9)

¿Cómo se crea la función setError() (similar a la de un TextView/EditText ) para un Spinner ? Lo siguiente no funciona:

Intenté extender la clase Spinner y en el constructor:

ArrayAdapter<String> aa = new ArrayAdapter<String>(getContext(), android.R.layout.simple_spinner_item, android.R.id.text1, items); aa.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); setAdapter(aa); tv = (TextView) findViewById(android.R.id.text1); // types_layout_list_tv ctv = (CheckedTextView) aa.getDropDownView(1, null, null); tv2 = (TextView) aa.getView(1, null, null);

Método setError :

public void setError(String str) { if (tv != null) tv.setError(str); if(tv2!=null) tv2.setError(str); if (ctv != null) ctv.setError(str); }


Usar un TextView oculto para que aparezca un mensaje emergente

Esta solución implica agregar un cuadro de texto oculto adicional justo debajo de la ruleta justo en la posición correcta para permitir que se muestre el cuadro de diálogo de error de TextView, y también usar el conjunto de TextView en el diseño XML del ruteador para mostrar el ícono rojo (!). Entonces, en efecto, se utilizan dos textviews: una para el icono y otra (oculta) para permitir el diálogo de error.

Esto es lo que parece cuando no está en un estado de error (use SetError(null) ):

Esto es lo que parece cuando hay un error (use SetError("my error text, ideally from a resource!") ):

Aquí está el extracto del diseño de spinner XML. Hay un RelativeLayout utilizado para garantizar que TextView esté lo más cerca posible del spinner, y tiene el paddingRight suficiente para garantizar que la flecha en el diálogo del mensaje esté alineada justo debajo del icono de error rojo (!). El TextView oculto (falso) se coloca en relación con el Spinner.

<RelativeLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="top|left" > <Spinner android:id="@+id/spnMySpinner" android:layout_width="400dp" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:dropDownSelector="@drawable/selector_listview" android:background="@android:drawable/btn_dropdown" android:paddingBottom="0dp" android:layout_marginBottom="0dp" /> <!-- Fake TextView to use to set in an error state to allow an error to be shown for the TextView --> <android.widget.TextView android:id="@+id/tvInvisibleError" android:layout_width="0dp" android:layout_height="0dp" android:layout_alignRight="@+id/spnMySpinner" android:layout_alignBottom="@+id/spnMySpinner" android:layout_marginTop="0dp" android:paddingTop="0dp" android:paddingRight="50dp" android:focusable="true" android:focusableInTouchMode="true" /> </RelativeLayout>

Nota: @drawable/selector_listview definido fuera del alcance de esta solución. Vea el ejemplo aquí sobre cómo hacer que esto funcione, ya que está fuera del tema de esta respuesta.

Aquí está el código para hacerlo funcionar. Simplemente llame al SetError(errMsg) con null para borrar el error o con texto para establecerlo en un estado de error.

/** * When a <code>errorMessage</code> is specified, pops up an error window with the message * text, and creates an error icon in the secondary unit spinner. Error cleared through passing * in a null string. * @param errorMessage Error message to display, or null to clear. */ public void SetError(String errorMessage) { View view = spnMySpinner.getSelectedView(); // Set TextView in Secondary Unit spinner to be in error so that red (!) icon // appears, and then shake control if in error TextView tvListItem = (TextView)view; // Set fake TextView to be in error so that the error message appears TextView tvInvisibleError = (TextView)findViewById(R.id.tvInvisibleError); // Shake and set error if in error state, otherwise clear error if(errorMessage != null) { tvListItem.setError(errorMessage); tvListItem.requestFocus(); // Shake the spinner to highlight that current selection // is invalid -- SEE COMMENT BELOW Animation shake = AnimationUtils.loadAnimation(this, R.anim.shake); spnMySpinner.startAnimation(shake); tvInvisibleError.requestFocus(); tvInvisibleError.setError(errorMessage); } else { tvListItem.setError(null); tvInvisibleError.setError(null); } }

En la función SetError anterior, ejemplo, hay un código adicional que causa que el texto en el Spinner se sacuda cuando se establece el error. Esto no es necesario para que la solución funcione, pero es una buena adición. Vea aquí para la inspiración de este enfoque.

Felicitaciones a @ Gábor por su solución que hace uso de TextView en el diseño de elementos de Spinner XML. El código View view = spnMySpinner.getSelectedView(); (basado en la solución de @Gabor) es necesario, porque obtiene el TextView actualmente visualizado, en lugar de usar un findViewById , que simplemente obtendría el primer TextView en la lista (basado en el ID de recurso provisto), y por lo tanto no funcionaría (para mostrar el ícono rojo (!) si el primer ítem de la lista no está seleccionado.


En realidad, esto es así, solo necesitas tener un solo TextView en tu Vista y luego obtener la Vista seleccionada desde tu spinner usando getSelectedView() si la Vista principal en tu Vista seleccionada es una Vista de TextView y luego TextView tu Vista directamente a TextView y setError Me gusta esto :

((TextView) jobCategory.getSelectedView()).setError("Field Required");

De lo contrario, si The Textview no es directamente la vista principal, entonces debe encontrarla por ID y volver a setError y setError esta manera:

((TextView) jobCategory.getSelectedView().findViewById(R.id.firstName)).setError("Field Required");


Esto se puede hacer sin usar un diseño o adaptador personalizado.

((TextView)spinner.getChildAt(0)).setError("Message");

El único inconveniente de este enfoque es que la pequeña ventana emergente con el texto de error no se mostrará cuando se toque el icono.


Gracias Gabor por su fantástica solución. En adelanto a su punto, mi solución es así:

Adaptador personalizado

public class RequiredSpinnerAdapter<T> extends ArrayAdapter<T> { public RequiredSpinnerAdapter(Context context, int textViewResourceId, java.util.List<T> objects) { super(context, textViewResourceId, objects); } int textViewId = 0; @Override public View getView(int position, View convertView, ViewGroup parent) { View view = super.getView(position, convertView, parent); if (view instanceof TextView) { textViewId = view.getId(); } return view; } public View getDropDownView(int position, View convertView, ViewGroup parent) { View row = super.getView(position, convertView, parent); return (row); } public void setError(View v, CharSequence s) { if(textViewId != 0){ TextView name = (TextView) v.findViewById(textViewId); name.setError(s); } } }

Use el adaptador para Spinner

ArrayAdapter<String> arrayAdapter = new RequiredSpinnerAdapter<String>(PropertyAdd.this, R.layout.checked, status_arr); marketstatus_spinner.setAdapter(arrayAdapter); marketstatus_spinner.setOnItemSelectedListener(new OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) { // Put code here } @Override public void onNothingSelected(AdapterView<?> arg0) { // Put code here } });

Verificar la validación

private boolean checkValidation() { if(marketstatus_spinner.getSelectedItem().toString().equals("")){ RequiredSpinnerAdapter adapter = (RequiredSpinnerAdapter)marketstatus_spinner.getAdapter(); View view = marketstatus_spinner.getSelectedView(); adapter.setError(view, "Please select a value"); return false; } }


Puede crear su propio adaptador (amplía BaseAdapter implementa SpinnerAdapter). De esta forma, puede acceder a las TextViews que se muestran en el control giratorio. (Métodos getView y createViewFromResource - ejemplo: ArrayAdapter ) Cuando agrega un elemento de la lista vacía para permitir que el usuario mantenga el campo vacío hasta que sea obligatorio (el primer elemento en la rueda giratoria), puede almacenarlo como un miembro privado en el adaptador . Luego, cuando llega el momento de llamar a setError ("...") desde la Actividad o Fragmento, puede llamarlo al adaptador que puede pasarlo al TextView vacío.

@Override public View getView(int position, View convertView, ViewGroup parent) { return createViewFromResource(position, convertView, parent, mTextViewId); } private View createViewFromResource(int position, View convertView, ViewGroup parent, int resource) { View view; TextView text; if (convertView == null) { view = inflater.inflate(resource, parent, false); } else { view = convertView; } try { text = (TextView) view; } catch (ClassCastException e) { Log.e(TAG, "You must supply a resource ID for a TextView", e); throw new IllegalStateException("MyAdapter requires the resource ID to be a TextView", e); } MyItem i = getItem(position); String s = (null != i) ? i.toString() : ""; text.setText(s); if ("".equals(s) && null == mEmptyText) { this.mEmptyText = text; } return view; } public void setError(String errorMessage) { if (null != mEmptyText) { mEmptyText.setError(errorMessage); } else { Log.d(TAG, "mEmptyText is null"); } }


Similar a la solución de @Gabor, pero no necesitaba crear mi propio adaptador. Acabo de llamar al siguiente código en mi función de validación (es decir, al hacer clic en el botón de enviar)

TextView errorText = (TextView)mySpinner.getSelectedView(); errorText.setError("anything here, just to add the icon"); errorText.setTextColor(Color.RED);//just to highlight that this is an error errorText.setText("my actual error text");//changes the selected item text to this


Supongo que Spinner no es el lugar correcto para poner este método. En el caso de Spinner, debe seleccionar un valor y los valores en el Spinner deben filtrarse en el nivel de su adaptador. Por lo tanto, un usuario puede elegir solo aquellos valores que están en el Spinner.


Te sugiero que coloques un EditText vacío justo detrás de tu spinner.

En el conjunto xml que EditText

android:enabled="false" android:inputType="none"

Ahora, cuando desee establecer un error para su spinner, simplemente configure ese error en EditText .

Recuerda no configurar ese EditText para invisibille / gone . No funcionará de esa manera.

Además, tenga en cuenta que con este método puede decidir exactamente dónde desea que aparezca su error.


Tengo una solución que no implica la creación de un campo de edición adicional, pero necesitas tu propio SpinnerAdapter , como de costumbre.

Asegúrese de tener al menos una TextView de TextView en el diseño que usa en getView() su adaptador (normalmente lo tiene).

Agregue la siguiente función a su adaptador (cambie el name a la ID de su TextView ):

public void setError(View v, CharSequence s) { TextView name = (TextView) v.findViewById(R.id.name); name.setError(s); }

Llame a setError() desde su código de esta manera:

YourAdapter adapter = (YourAdapter)spinner.getAdapter(); View view = spinner.getSelectedView(); adapter.setError(view, getActivity().getString(R.string.error_message));

Básicamente, como con cualquier otro control, solo debe llamarlo a su adaptador y también debe proporcionar la vista.

Esto mostrará el icono de error en la ruleta como es el caso con otros controles.