Android 如何在外部点击时将文本保留在 EditText 中?

Android How to keep text in EditText when taping outside?

当我输入 EditText 并点击屏幕的另一部分时,EditText 中的文本消失了(就像键盘 closes/hides 时一样)。

EditText 是密码输入,当前显示在 AlertDialog.Builder:

final AlertDialog.Builder passwordInputDialog =  new AlertDialog.Builder(MainActivity.this, R.style.CustomAlertDialog);
TextInputLayout passwordInputLayout           = new TextInputLayout(MainActivity.this);
passwordInputInflater                         = LayoutInflater.from(MainActivity.this).inflate(R.layout.password_input, null);

passwordInputDialog
    .setCustomTitle(passwordInputTextView)
    .setMessage(message)
    .setView(passwordInputLayout)
    .setPositiveButton("OK", onPositiveAlertDialogClick())
    .setNegativeButton("Cancel", onNegativeAlertDialogClick());

final AlertDialog passwordInputShownDialog = passwordInputDialog.show();
final EditText enteredPassword = passwordInputInflater.findViewById(R.id.etPassword);

EditText 附加了一个 addTextChangedListener 事件,可以很好地执行任何其他操作:

enteredPassword.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 enteredText) {
        ...
        enteredPassword.removeTextChangedListener(this);
        enteredPassword.setText(enteredText);
        enteredPassword.setSelection(enteredText.length());
        enteredPassword.addTextChangedListener(this);
    }
});

问题是如果我做错了什么,或者是对话框中 EditText 的默认行为 "when leaving the input"。

我该怎么做才能"preserve" 在此之外点击后立即在 EditText 中输入的文本?


这是我尝试在 afterTextChanged 函数上设置 EditText 的文本时得到的结果:

2019-11-24 20:20:46.795 20941-20954/com.example.map2 I/om.example.map: Background concurrent copying GC freed 135477(4MB) AllocSpace objects, 0(0B) LOS objects, 50% free, 9MB/18MB, paused 79us total 113.470ms
2019-11-24 20:20:54.553 20941-20954/com.example.map2 I/om.example.map: Background concurrent copying GC freed 136023(4MB) AllocSpace objects, 0(0B) LOS objects, 49% free, 10MB/21MB, paused 89us total 128.803ms
2019-11-24 20:21:03.751 20941-20954/com.example.map2 I/om.example.map: Background concurrent copying GC freed 137630(4MB) AllocSpace objects, 0(0B) LOS objects, 50% free, 12MB/25MB, paused 108us total 162.638ms
2019-11-24 20:21:13.794 20941-20954/com.example.map2 I/om.example.map: Background concurrent copying GC freed 137787(4MB) AllocSpace objects, 0(0B) LOS objects, 50% free, 14MB/28MB, paused 110us total 153.423ms
2019-11-24 20:21:24.617 20941-20954/com.example.map2 I/om.example.map: Background concurrent copying GC freed 137118(4MB) AllocSpace objects, 0(0B) LOS objects, 50% free, 16MB/32MB, paused 101us total 181.131ms

它冻结了应用程序,我不得不终止它。

我理解并意识到我需要的不是那样做。因为我想保存用户在 SharedPreferences 中写入的内容以再次显示它们,这样用户就不必多次键入内容。

关闭alertDialog,里面的所有数据都会丢失。 您可以通过以下方式阻止关闭 alertDialog:

passwordInputDialog.setCancelable(false);

或者您可以将最后一个值保存在 alertDialog 中,并通过再次显示将其取回。 (不推荐)

To Answer your question, the editText is not the one disappearing! It's the dialog and since the dialog is the one hosting the editText, onCancle of the dialog simply takes away the editText also if that's exactly what you're doing.

Note: Pay attention to the comments in the code below.

第一次观察:

enteredPassword.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 enteredText) {
        ...
        enteredPassword.removeTextChangedListener(this); /* why this? when you will still add it back immediately below? */
        enteredPassword.setText(enteredText); /*Change to enteredText.toString() because enteredText is an interface and you need to point to the method toString to get the character array inside it.*/
        enteredPassword.setSelection(enteredText.length()); /*Not sure why you're using this either */
        enteredPassword.addTextChangedListener(this); /*why this? when you're already listening?*/
    }
});

This can replace what you currently have about the enterPassword above:

enteredPassword.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 enteredText) {
    enteredPassword.setText(enteredText.toString()); /* although this is actually weird! in the sense that enteredPassword already has the text and yet, you're still assigning it texts back to itself, I mean enteredPassword.setText(enteredPassword.getText().toString() is equivalent to enteredText.toString())*/
    }
});

Also: Since you said the editText is in the dialog, then you should not be seeing the editText if the Dialog actually dismisses, Well, I guess the dialog did not dismiss and on the same dialog you're trying to do something else and when the focus change from the editText to another View on the Dialog, then the texts in the EditText for enter password is gone? if Yes: Then you actually don't need the TextChange listeners if all you need is the texts, simple create a variable to store the text and use as you want.

Finally: My question is what are you trying to do in particular? don't be scare to ask more elaborative questions, you just need to be specific.