Comment créez-vous la fonction setError()
(similaire à celle d'un TextView/EditText
) pour un Spinner
? Ce qui suit ne fonctionne pas:
J'ai essayé d'étendre la classe Spinner et dans le constructeur:
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);
setError
méthode:
public void setError(String str) {
if (tv != null)
tv.setError(str);
if(tv2!=null)
tv2.setError(str);
if (ctv != null)
ctv.setError(str);
}
Semblable à la solution de @ Gábor, mais je n'avais pas besoin de créer mon propre adaptateur. J'appelle simplement le code suivant dans ma fonction de validation (c'est-à-dire en cliquant sur le bouton d'envoi)
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
J'ai une solution qui ne nécessite pas la création d'un champ de saisie supplémentaire, mais vous avez besoin de votre propre variable SpinnerAdapter
, comme d'habitude.
Assurez-vous d’avoir au moins une TextView
dans la présentation que vous utilisez dans la fonction getView()
de votre adaptateur (de toute façon, vous l’avez normalement).
Ajoutez la fonction suivante à votre adaptateur (remplacez name
par l'ID de votre TextView
):
public void setError(View v, CharSequence s) {
TextView name = (TextView) v.findViewById(R.id.name);
name.setError(s);
}
Appelez la setError()
à partir de votre code de cette façon:
YourAdapter adapter = (YourAdapter)spinner.getAdapter();
View view = spinner.getSelectedView();
adapter.setError(view, getActivity().getString(R.string.error_message));
Fondamentalement, comme pour tout autre contrôle, vous l’appelez uniquement sur votre adaptateur et vous devez également fournir la vue.
Ceci affichera l’icône d’erreur sur la roulette comme c’est le cas avec les autres contrôles.
Cette solution implique l'ajout d'une zone de texte masquée supplémentaire juste sous le compteur, juste au bon endroit, afin de permettre à la boîte de dialogue d'erreur de TextView de s'afficher, tout en utilisant le paramètre TextView défini dans le XML de présentation du compteur pour permettre à l'icône rouge (!) D'être affichée. En réalité, deux vues de texte sont utilisées: une pour l'icône et une autre (masquée) pour autoriser le dialogue d'erreur.
Voici à quoi cela ressemble quand il n'y a pas d'erreur (utilisez SetError(null)
):
Voici à quoi ça ressemble quand il y a une erreur (utilisez SetError("my error text, ideally from a resource!")
):
Voici l'extrait de la mise en page XML du spinner. Il existe un RelativeLayout utilisé pour garantir que le TextView est aussi proche que possible de la roulette et a juste assez de paddingRight pour que la flèche de la boîte de dialogue du message soit alignée juste en dessous de l'icône d'erreur rouge (!). Le TextView masqué (faux) est positionné par rapport au 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>
Remarque: @drawable/selector_listview
défini en dehors de la portée de cette solution. Voir exemple ici sur la façon de faire fonctionner ceci, car il est hors sujet pour cette réponse.
Voici le code pour le faire fonctionner. Appelez simplement la SetError(errMsg)
soit avec null
pour effacer l'erreur, soit avec du texte pour la définir dans un état d'erreur.
/**
* 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);
}
}
Dans la fonction SetError
ci-dessus, par exemple, il existe un code supplémentaire qui fait trembler le texte dans le Spinner lorsque l'erreur est définie. Ce n'est pas nécessaire pour que la solution fonctionne, mais c'est un ajout agréable. Voir ici pour l'inspiration de cette approche.
Félicitations à @ Gábor pour sa solution qui utilise TextView sur le format XML de Spinner's layout. Le code View view = spnMySpinner.getSelectedView();
(basé sur la solution de @ Gábor) est nécessaire, car il récupère le TextView actuellement affiché, plutôt que d'utiliser une findViewById
, qui obtiendrait simplement le premier TextView de la liste (basé sur l'ID de ressource fourni), et par conséquent travail (pour afficher l’icône rouge (!)) si le tout premier élément de la liste n’est pas sélectionné.
Cela peut être fait sans utiliser une mise en page personnalisée ou un adaptateur.
((TextView)spinner.getChildAt(0)).setError("Message");
Le seul inconvénient de cette approche est que le petit popup avec le texte d'erreur ne s'affichera pas lorsque l'icône sera exploitée.
Je vous suggère de mettre une EditText
vide juste derrière votre casserole.
Sur le jeu xml que EditText
Android:enabled="false"
Android:inputType="none"
Maintenant, lorsque vous voulez définir une erreur sur votre compteur, définissez simplement cette erreur sur EditText
.
N'oubliez pas de définir EditText
sur invisibille
/gone
. Cela ne fonctionnera pas comme ça.
Notez également que par cette méthode, vous pouvez décider exactement où vous voulez que votre erreur apparaisse.
Merci Gabor pour votre solution fantastique. Dans la suite de votre propos, ma solution est donc la suivante:
Adaptateur personnalisé
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);
}
}
}
Utilisez l'adaptateur pour 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
}
});
Vérifier la validation
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;
}
}
Je suppose que Spinner n'est pas le bon endroit pour mettre cette méthode. Dans le cas de Spinner, vous devez sélectionner une valeur et filtrer les valeurs dans Spinner au niveau de votre adaptateur. Ainsi, un utilisateur ne peut choisir que les valeurs qui se trouvent dans le compteur.
En fait, c’est très, il vous suffit de n’avoir qu’une seule variable TextView
dans votre vue, puis d’obtenir la vue sélectionnée de votre visionneuse à l’aide de getSelectedView()
si la vue principale de la vue sélectionnée est une TextView
, puis convertissez directement votre vue en TextView
et setError
comme ceci. :
((TextView) jobCategory.getSelectedView()).setError("Field Required");
Sinon, si TextView n'est pas directement la vue PRINCIPALE, vous devez le rechercher par ID, puis le relancer et setError
de cette façon:
((TextView) jobCategory.getSelectedView().findViewById(R.id.firstName)).setError("Field Required");
Vous pouvez créer votre propre adaptateur (l'extension BaseAdapter implémente SpinnerAdapter). De cette façon, vous pouvez accéder aux TextViews qui sont affichés dans le disque. (Méthodes getView et createViewFromResource - exemple: ArrayAdapter ) Lorsque vous ajoutez un élément de liste vide pour permettre à l'utilisateur de conserver le champ vide jusqu'à ce qu'il devienne obligatoire (premier élément dans le compteur), vous pouvez stocker son TextView en tant que fichier privé membre dans l'adaptateur. Ensuite, lorsque vient le temps d'appeler setError ("...") à partir de l'activité ou du fragment, vous pouvez l'appeler sur l'adaptateur, qui peut le transmettre à TextView vide.
@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");
}
}