Android EditText 符号必须保持在初始位置

Android EditText Symbol must remain at initial position

我有一个文本字段,其起始符号是 $(可以是欧元或英镑,具体取决于应用程序设置)。我需要这样做,以便如果用户在符号之前单击什么也不会发生。换句话说,选择必须保留在符号之后。我尝试做这样的事情,但它似乎是错误的,它给了我一个错误:

billAmount.addTextChangedListener(new TextWatcher() {

    //other methods 

    @Override
    public void afterTextChanged(Editable s) {
        billAmount.setText(currencySymbol + billAmount.getText().toString());
    }
});

我正在考虑使用 inputFilter,但我尝试过但没有任何效果。我也不允许在 EditText 之前使用 TextView。

我猜你得到了 WhosebugException
试试这个
String oldValue="";//instace variable

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        //bilamount always starts with your currency symbol
        if (s != null && s.length() == 0) {
            editText.setText("$");
            editText.setSelection(1);
        }

        if (s != null && s.length() > 0) {
            String billAmount = s.toString();
            if (!oldValue.equals(billAmount)) {//minimize unnecessary setText() method call
                oldValue= billAmount;
                editText.setText(billAmount);
                editText.setSelection(billAmount.length());
            }
        }

    }   

注意: 你的 EditText 首先用你的 currencySymbol 初始化,即
billAmount.setText(currencySymbol);

首先,在您的代码示例中,出现错误的原因是,正如其他人所说,您在 afterTextChanged 方法中调用了 setText 方法。调用 setText 显然是在更改导致再次调用 afterTextChanged 的文本。这导致 afterTextChanged 被连续调用,直到最终出现堆栈溢出。

您有两个问题:1) 您希望始终将光标定位在货币符号之后,以及 2) 您希望确保货币符号永远不会以某种方式被删除。

解决#1 的最简单方法是创建 EditText 的子类并覆盖 onSelectionChanged 方法。

public class MyEditText extends EditText {

    // ...

    @Override
    public void onSelectionChanged(int selStart, int selEnd) {
        super.onSelectionChanged(selStart, selEnd);

        // Make sure the text's length is greater than zero.
        // Then, if the cursor is at position zero...
        if (getText().length() > 0 && selStart == 0) {
            // ...move it over to position one.
            setSelection(1, selEnd);
        }
    }
}

这将强制光标始终位于货币符号之后,即使用户试图将其移动到它之前也是如此。检查getText().length() > 0是为了确保EditText包含至少一个字符,否则尝试移动光标将导致异常。

至于#2,有几种方法可以解决。您可以尝试在 TextWatcher 中使用一些实例变量来跟踪何时需要格式化文本,但这不会阻止实际发生不必要的方法调用,并且会增加一些不必要的复杂性。我认为简单地使用 InputFilter 会更容易,您可以在扩展的 EditText 的构造函数中指定它。

public class MyEditText extends EditText {

    public MyEditText(Context context) {
        super(context);

        // Set the EditText's input filter.
        setFilters(new InputFilter[] { new InputFilter {
            @Override
            public CharSequence filter(CharSequence source, int start, int end,
                                        Spanned dest, int dstart, int dend) {
                // If the currency symbol is about to be replaced...
                if (dstart == 0)
                    // Add the currency symbol to the front of the source.
                    return currencySymbol + source;
                // else
                    // Return null to indicate that the change is okay.
                    return null;
            } 
        }});
    }

    // ...
}

filter方法中,dest参数表示EditText的文本,dstartdend参数表示开始和即将被替换的文本部分的结束位置。由于货币符号应始终是第一个字符,如果 dstart 为零,我们知道它将被替换,在这种情况下,我们只需 return source (表示替换文本),货币符号放在前面。否则,我们通过 returning null.

表明更改是正确的

我测试了它,它似乎可以满足你的需要。

附带说明一下,虽然我知道您 "allowed" 不适合使用 TextView,但我认为值得重申的是,使用 TextView 可以更好地解决此问题。一个特别有用的解决方案是隐藏 EditText 包含来自用户的原始输入,并在 EditText 之上添加 TextView。您可以使用 TextWatcher 来更新 TextView,并使用来自 EditText.

的格式正确的输入