webentwicklung-frage-antwort-db.com.de

Ein setError () für den Spinner erstellen

Wie erstellen Sie die Funktion setError() (ähnlich einer TextView/EditText) für eine Spinner? Folgendes funktioniert nicht:

Ich habe versucht, die Spinner-Klasse und den Konstruktor zu erweitern:

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 Methode:

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

Ähnlich wie bei @ Gábor, aber ich musste keinen eigenen Adapter erstellen. Ich rufe einfach den folgenden Code in meiner Überprüfungsfunktion auf (d. H. Beim Klicken auf "Senden".)

        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
39
EdmundYeung99

Ich habe eine Lösung, bei der kein zusätzliches Editierfeld erstellt wird, Sie benötigen jedoch wie üblich Ihre eigene SpinnerAdapter.

Vergewissern Sie sich, dass Sie mindestens eine TextView in dem Layout haben, das Sie in der getView() Ihres Adapters verwenden (dies ist normalerweise der Fall).

Fügen Sie Ihrem Adapter folgende Funktion hinzu (ändern Sie name in die ID Ihrer TextView):

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

Rufen Sie die setError() aus Ihrem Code auf folgende Weise auf:

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

Grundsätzlich gilt, wie bei jedem anderen Steuerelement, nur, dass Sie es auf Ihrem Adapter aufrufen und die Ansicht ebenfalls bereitstellen müssen.

Dadurch wird das Fehlersymbol auf dem Spinner angezeigt, wie dies bei anderen Steuerelementen der Fall ist.

20
Gábor

Verwenden einer ausgeblendeten Textansicht, um eine Popup-Meldung anzuzeigen

Diese Lösung umfasst das Hinzufügen eines zusätzlichen ausgeblendeten Textfelds direkt unterhalb des Drehfelds genau an der richtigen Position, damit das Fehlerdialogfeld von TextView angezeigt werden kann. Außerdem wird das TextView-Set im Layout-XML des Drehfelds verwendet, um das rote Symbol (!) Anzuzeigen. Es werden also zwei Textansichten verwendet - eine für das Symbol und eine (verborgene) für den Fehlerdialog.

So sieht es aus, wenn es sich nicht in einem Fehlerzustand befindet (verwenden Sie SetError(null)):

Spinner in valid state

So sieht es aus, wenn ein Fehler auftritt (verwenden Sie SetError("my error text, ideally from a resource!")):

Spinner in invalid state

Hier ist der Auszug aus dem XML-Layout des Spinners. Es wird ein RelativeLayout verwendet, um sicherzustellen, dass sich die TextView so nahe wie möglich am Spinner befindet und gerade genug paddingRight vorhanden ist, um sicherzustellen, dass der Pfeil im Nachrichtendialogfeld unter dem roten Fehlersymbol (!) Ausgerichtet ist. Die versteckte (gefälschte) TextView wird relativ zum Spinner positioniert.

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

Hinweis: @drawable/selector_listview wird außerhalb des Umfangs dieser Lösung definiert. Siehe Beispiel hier , wie man dies zum Laufen bringt, da es für diese Antwort ein Thema ist.

Hier ist der Code, damit es funktioniert. Rufen Sie einfach SetError(errMsg) entweder mit null auf, um den Fehler zu löschen, oder mit Text, um ihn in einen Fehlerzustand zu setzen.

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

In der obigen Funktion SetError gibt es einen zusätzlichen Code, der dazu führt, dass der Text im Spinner beim Setzen des Fehlers verwackelt. Dies ist nicht erforderlich, um die Lösung zum Laufen zu bringen, ist jedoch eine nette Ergänzung. Siehe hier für die Inspiration für diesen Ansatz.

Ein dickes Lob an @ Gábor für seine Lösung , die die TextView im XML-Elementlayout des Spinners verwendet. Der Code View view = spnMySpinner.getSelectedView(); (basierend auf der Lösung von @ Gábor) ist erforderlich, da er die aktuell angezeigte TextView abruft, anstatt eine findViewById zu verwenden, die lediglich die erste TextView in der Liste abrufen würde (basierend auf der bereitgestellten Ressourcen-ID) und daher nicht work (um das rote (!) Symbol anzuzeigen), wenn der erste Eintrag in der Liste nicht ausgewählt ist.

10
CJBS

Dies kann ohne Verwendung eines benutzerdefinierten Layouts oder Adapters erfolgen.

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

Der einzige Nachteil dieses Ansatzes ist, dass das kleine Popup mit dem Fehlertext nicht angezeigt wird, wenn auf das Symbol getippt wird.

6
Jarett Millard

Ich würde dir vorschlagen, ein leeres EditText direkt hinter deinen Spinner zu legen.

Legen Sie in der XML-Datei fest, dass EditText 

Android:enabled="false"
    Android:inputType="none"

Wenn Sie jetzt einen Fehler für Ihren Spinner festlegen möchten, setzen Sie diesen Fehler einfach auf EditText.

Denken Sie daran, dass EditText nicht invisibille/gone gesetzt ist. So wird es nicht funktionieren.

Beachten Sie außerdem, dass Sie mit dieser Methode genau entscheiden können, wo der Fehler angezeigt werden soll.

5
EladHackim

Danke, Gabor, für deine fantastische Lösung. Im Hinblick auf Ihren Punkt ist meine Lösung also:

Kundenspezifischer Adapter

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

Verwenden Sie einen Adapter für den 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
        }
    });

Überprüfen Sie die Validierung

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

Ich denke, dass Spinner nicht der richtige Ort für diese Methode ist. Im Falle von Spinner sollten Sie einen Wert auswählen und die Werte im Spinner sollten auf der Ebene Ihres Adapters gefiltert werden. Daher kann ein Benutzer nur die Werte auswählen, die sich im Spinner befinden.

0
Yury

Eigentlich ist dies sehr, Sie brauchen nur eine TextView in Ihrer Ansicht und dann die ausgewählte Ansicht von Ihrem Spinner mit getSelectedView() abzurufen, wenn die Hauptansicht in Ihrer ausgewählten Ansicht eine TextView ist, und wandeln Sie Ihre Ansicht direkt in TextView und setError wie folgt :

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

Andernfalls, wenn The Textview nicht direkt die MAIN-Ansicht ist, müssen Sie sie anhand der ID suchen und erneut umwandeln und setError folgendermaßen: 

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

Sie können Ihren eigenen Adapter erstellen (erweitert BaseAdapter implementiert SpinnerAdapter). Auf diese Weise können Sie auf die im Spinner angezeigten TextViews zugreifen. (Methoden getView und createViewFromResource - Beispiel: ArrayAdapter ) Wenn Sie ein leeres Listenelement hinzufügen, damit der Benutzer das Feld leer lassen kann, bis es obligatorisch ist (erstes Element im Spinner), können Sie dessen TextView als privat speichern Mitglied im Adapter. Wenn dann der Aufruf von setError ("...") aus der Aktivität oder dem Fragment erfolgt, können Sie es auf dem Adapter aufrufen, der es an die leere TextView übergeben kann. 

@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");
    }
}
0
j00ris