Validating EditTextPreference on Android
Asked Answered
D

4

9

I have read the many answers on this question but my question is asking where I place the code. I am looking to validate that a number is greater than 100 in the EditTextPreference. This is the code I use to populate the preferences:

public class SettingsFrag extends PreferenceFragment{
          
  //Override onCreate so that the code will run when the activity is started.
  @Override
  public void onCreate(Bundle savedInstanceState){        
          //Call to the super class.
          super.onCreate(savedInstanceState);
          
          //add the preferences from the XML file.
          addPreferencesFromResource(R.xml.preferences);
  }

}

Is it in here I add the validation or would I have to create another class?

preferences.xml:

<EditTextPreference             
    android:key="geofence_range"             
    android:title="Geofence Size"             
    android:defaultValue="500"     
    android:inputType="number"
    android:summary="Geofence Size Around User Location"             
    android:dialogTitle="Enter Size (meters):" /> 
Dorey answered 18/2, 2014 at 14:34 Comment(0)
N
16

Add setOnPreferenceChangeListener for EditTextPreference after addPreferencesFromResource to validate data input for User:

EditTextPreference edit_Pref = (EditTextPreference) 
                    getPreferenceScreen().findPreference("geofence_range");
   edit_Pref.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {

     @Override
      public boolean onPreferenceChange(Preference preference, Object newValue) {
          // put validation here..
            if(<validation pass>){
              return true;
            }else{
              return false;
             }
       }
    });
Ninety answered 18/2, 2014 at 14:44 Comment(1)
works for me but i set the listener in onCreatePreferencesArchaism
B
12

Note: This answer is based on the deprecated android.preference.EditTextPreference.


Huh. Another one of those things that should be so darned easy in Android but isn't. Other answers just silently prevent writing back the result to preferences, which seems a bit shoddy. (Showing toast is less shoddy, but is still shoddy).

You'll need a custom preference to do this. Customize onValidate to suit your needs.

package com.two_play.extensions;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.preference.EditTextPreference;
import android.util.AttributeSet;
import android.view.View;
import android.widget.EditText;

public class ValidatingEditTextPreference extends EditTextPreference {
    public ValidatingEditTextPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    public ValidatingEditTextPreference(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public ValidatingEditTextPreference(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public ValidatingEditTextPreference(Context context) {
        super(context);
    }

    @Override
    protected void showDialog(Bundle state) {
        super.showDialog(state);
        AlertDialog dlg = (AlertDialog)getDialog();
        View positiveButton = dlg.getButton(DialogInterface.BUTTON_POSITIVE);
        getEditText().setError(null);
        positiveButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onPositiveButtonClicked(v);
            }
        });
    }

    private void onPositiveButtonClicked(View v) {
        String errorMessage = onValidate(getEditText().getText().toString());
        if (errorMessage == null)
        {
            getEditText().setError(null);
            onClick(getDialog(),DialogInterface.BUTTON_POSITIVE);
            getDialog().dismiss();
        } else {
            getEditText().setError(errorMessage);
            return; // return WITHOUT dismissing the dialog.
        }
    }

    /***
     * Called to validate contents of the edit text.
     *
     * Return null to indicate success, or return a validation error message to display on the edit text.
     *
     * @param text The text to validate.
     * @return An error message, or null if the value passes validation.
     */
    public String onValidate(String text)
    {
        try {
            Double.parseDouble(text);
            return null;
        } catch (Exception e)
        {
            return getContext().getString(R.string.error_invalid_number);
        }
    }
}
Beesley answered 10/7, 2015 at 16:11 Comment(2)
I couldn't find the showDialog method in the EditTextPreference class. Please help!Tiberias
@Tiberias I believe you are using the new androidx.preference:preference library. The showDialog method is no longer exposed as public in the EditTextPreference. The answer above refers to the deprecated android.preference.EditTextPreference.Hightower
S
3

It seems more elegant to me to disable the "OK" button instead of allowing the user to press it but then discard their input and show the error. getDialog seems to be gone in androidx.preference, but this seems to work for me instead:

final EditTextPreference p = new EditTextPreference(context);
p.setOnBindEditTextListener(new EditTextPreference.OnBindEditTextListener() {
    @Override
    public void onBindEditText(@NonNull final EditText editText) {
        editText.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
            }

            @Override
            public void afterTextChanged(Editable editable) {
                String validationError;
                try {
                    // ... insert your validation logic here, throw on failure ...
                    validationError = null; // All OK!
                } catch (Exception e) {
                    validationError = e.getMessage();
                }
                editText.setError(validationError);
                editText.getRootView().findViewById(android.R.id.button1)
                        .setEnabled(validationError == null);
            }
        });
    }
});
Selfconfessed answered 12/12, 2019 at 3:0 Comment(0)
H
1

Here is my Kotlin implementation for androidx.preference.* based on Vladimir Panteleev's answer:

class CustomPreference : EditTextPreference {


    // ...

    private fun applyValidation() = setOnBindEditTextListener { editText ->
        editText.doAfterTextChanged { editable ->
            requireNotNull(editable)
            // TODO Add validation magic here.
            editText.error = if (criteria.isValid()) {
                null // Everything is fine.
            } else {
                if (criteria.getErrorMessage() == null) "Unknown validation error"
                else resources.getString(criteria.getErrorMessage())
            }
        }
    }

}

The handy doAfterTextChanged extension is part of the androidx.core:core-ktx library.

Hightower answered 12/9, 2020 at 19:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.