Не закрывайте DialogPreference onClick, если условие не выполнено - PullRequest
4 голосов
/ 01 апреля 2012

Мне нужно для AutoCompliteTextView в PreferenceActivity, поэтому я расширил DialogPreference. Мой автокомплит ожидает от (помощи) пользователя ввода названия страны. Я в порядке, если пользователь нажимает Отмена или не вводит никаких значений, однако я хотел бы убедиться, что правильное имя введено до закрытия диалога. Я пытался переопределить onClick как


@Override
public void onClick(DialogInterface dialog, int which) {
        if (!validator.isValid(textView.toString())) {
            onDialogClosed(false);
        } else {
            //do something here
            super.onClick(dialog, which);
        }
    }

также с onDialogClosed


@Override
    protected void onDialogClosed(boolean positiveResult) {
        if (validator.isValid(textView.toString())) {
            //do something here
            super.onDialogClosed(positiveResult);
        }
    }

Ответы [ 5 ]

9 голосов
/ 11 ноября 2013

Я также столкнулся с проблемой, заключающейся в том, что Android не предоставляет встроенного способа проверки вновь введенного значения предпочтения ДО закрытия диалогового окна предпочтений. Проверка, выполненная после закрытия диалогового окна (что выполняет boolean onPreferenceChange), может только обнаружить, что значение является неправильным и приложение должно предотвратить его сохранение, но это кажется довольно неудобным. Просто представьте, что пользователь сделал опечатку, новое значение не сохраняется, но диалоговое окно закрыто, и пользователю сообщают, что он / она должен повторить процесс с самого начала. Это обязательно должно быть исправлено.

Когда возникает проблема в программировании, лучше предоставить код для решения. Вот почему я публикую ответ с готовым решением для копирования и вставки. Это следует из очевидной идеи из одного из приведенных выше ответов, в то время как в нем не рассматриваются отражения, как подразумевает другой предоставленный фрагмент кода.

public class CustomEditTextPreference extends EditTextPreference
{
  // if true, this preference requires new values to be checked for conformance to e-mail syntax
  private boolean isEmail = false; 

  public CustomEditTextPreference(Context context, AttributeSet attrs)
  {
    super(context, attrs);

    // set isEmail either from custom XML-attributes (look up through attrs)
    // or just by key
    // if(getKey().equals(KNOWN_EMAIL_PREF))
    //   isEmail = true;
  }

  /**
   * Checks if newValue conforms to a specific rule/syntax.
   * Returns error code equal to resource ID of corresponding error message if the value is incorrect,
   * or 0 if the validation was successful
   *
   * @param  newValue  a string with new preference value that needs a check-up
   * @return    integer error code equal to error message resource id
   */
  private int isValid(String newValue)
  {
    int result = 0; // no error

    if(isEmail) 
    {
      if(!android.util.Patterns.EMAIL_ADDRESS.matcher(newValue).matches())
      {
        result = R.string.invalid_email;
      }
    }
    // ...
    // other check-ups if necessary

    return result;
  }

  @Override
  protected void showDialog(Bundle state)
  {       
    super.showDialog(state);

    final AlertDialog d = (AlertDialog)getDialog();

    final EditText edit = getEditText();

    d.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener()
    {            
      @Override
      public void onClick(View v)
      {
        int errorCode = isValid(edit.getText().toString());
        Boolean canCloseDialog = (errorCode == 0);

        if(canCloseDialog)
        {
          d.dismiss();
          onDialogClosed(true);
        }
        else
        {
          String errorMessage = getContext().getString(errorCode);
          Toast t = Toast.makeText(getContext(), errorMessage, Toast.LENGTH_LONG);
          t.setGravity(Gravity.CENTER, 0, 0);
          t.show();
        }
      }
    });
  }
}

Я думаю, что код в значительной степени самоочевиден. Если пользователь заполняет поле с неправильным адресом электронной почты и нажимает кнопку ОК, то диалоговое окно остается открытым, и через тост отображается сообщение об ошибке.

6 голосов
/ 13 апреля 2013

На самом деле, используя reflection, я достиг того, что вы сказали.

@Override
public void onClick(DialogInterface dialog, int which) {
    if(!validate(arg)){
        try {
            // do not close
            Field field = dialog.getClass().getSuperclass()
                    .getDeclaredField("mShowing");
            field.setAccessible(true);
            field.set(dialog, false);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
4 голосов
/ 01 апреля 2012

Как только пользователь нажимает на кнопку диалога, диалог закрывается, и вы ничего не можете сделать, чтобы остановить его.

Единственное, что я могу придумать, это попытаться вызвать getDialog() на DialogPreference, привести его к AlertDialog, затем вызвать getButton(), чтобы получить положительную кнопку и отключить ее, включив ее. позже, когда ввод действителен.

2 голосов
/ 18 февраля 2014

Если вы хотите показать некоторую ошибку в диалоговом окне вместо отключения кнопки, вам нужно создать класс CustomEditTextPreference, который расширяет EditTextPreference

ниже приведен фрагмент кода

public class CustomEditTextPreference extends EditTextPreference  {
EditText setPasswordEditText;
private Context context;
AlertDialog alertDialog;

public CustomEditTextPreference(Context context, AttributeSet attrs) {
    super(context, attrs);
    this.context = context;
    setPasswordEditText = this.getEditText();
}

@Override
protected void showDialog(Bundle state) {
    super.showDialog(state);

    alertDialog = (AlertDialog) getDialog();
    alertDialog.setCanceledOnTouchOutside(false);
    Button positiveButton = alertDialog
            .getButton(AlertDialog.BUTTON_POSITIVE);
    positiveButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            String str = setPasswordEditText.getText().toString();
            if (/*condition not met*/) {
                showError();
            } else {
                alertDialog.dismiss();
            }

        }
    });

}
1 голос
/ 02 октября 2014

Вы можете переопределить onPrepareDialogBuilder () внутри DialogPreference

...