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

时间:2015-06-09 02:44:57

标签: java android android-edittext android-input-filter

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

billAmount.addTextChangedListener(new TextWatcher() {

    //other methods 

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

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

2 个答案:

答案 0 :(得分:1)

首先,在您的代码示例中,您收到错误的原因是,正如其他人所说,您在setText方法中调用了afterTextChanged方法。调用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为零,它将被替换,在这种情况下,我们只需返回source(代表替换文本)的货币符号放在前面。否则,我们通过返回null来表明更改是可以的。

我测试了它,它似乎适用于你需要的东西。

另一方面,虽然我明白你并没有"允许"使用TextView,我认为值得重申的是,使用一个可以为这个问题提供更好的解决方案。一个特别有用的解决方案是让隐藏的EditText包含来自用户的原始输入,并使TextView位于EditText之上。您可以使用TextWatcher使用TextView中格式正确的输入更新EditText

答案 1 :(得分:0)

我猜你得到了StackOverFlowException
试试这个 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);