我正在开发一个Android应用程序,我有一个EditText,用户可以输入数字。我想使用不同的货币格式(比如##,##,###)格式化数字,我想在运行中进行,即当用户输入每个数字时(而不是按下输入时)。我google了一下,遇到了TextWatcher我最初发现有希望,但结果却是一种绝对的痛苦。我正在使用只有软键盘的HTC Desire手机上调试我的代码。
现在我想在用户按下数字(0到9),del(退格)键并输入密钥时收到回调。从我的测试中我发现了这些(至少在我的手机上)
1)调用editText onKeyListener 当用户按del或输入密钥时。 当用户按Enter键时,onKey 一次输入调用两次函数 (我认为是ACTION_UP和 ACTION_DOWN)。当用户按del时, onKey被调用一次(仅用于 ACTION_DOWN)我不知道为什么。 用户永远不会调用onKey 按下任何数字(0到9)我也是 不明白。
2)TextWatchers 3个回调函数 被称为(beforeTextChanged, onTextChanged,afterTextChanged) 每当用户按下任何数字(0到 9)关键。所以我想通过使用 TextWatcher和onKeyListener在一起 我可以得到我需要的所有回调。
现在我的问题是这些......
1)首先在我的HTC软键盘上 是一把钥匙(带有键盘的键盘符号) 向下箭头)当我点击它 键盘没有给予辞职 任何回调。我还是不敢相信 android让用户编辑一个字段 并且不让程序进行辞职 处理(保存)编辑。现在我的 editText显示一个值和我的 对象有另一个值(我正在保存 用户在输入和处理时进行编辑 通过重置按键盘上 editText值与值中的值 对象,但我没有答案 键盘向下键)。
2)其次,我想格式化数字 用户输入新数字后。说 我在editText上已经有123了 用户输入按4,我想要我的 editText显示1,234。我满满的 onTextChanged()和。上的数字 afterTextChanged()我可以格式化 这个数字并把它还给了 任何这些回调中的editText。 我应该使用哪一个?哪一个是 最佳实践?
3)第三个是最重要的 问题。当应用程序启动我把它 editText中的当前对象值。 假设我将123放在onResume()上,以及何时 用户输入一个数字(比如4)我想要它 是1234.但在我的onTextChanged 回调我得到的是4123.什么时候 我再按一个键(比如说5) 得到45123.所以对于用户输入 editText游标指向的结尾 文本。但是当价值设定时 手,editText光标似乎不是 更新。我相信我必须这样做 textWatcher回调中的东西但是 我不知道该怎么做。
我在下面发布我的代码。
public class AppHome extends AppBaseActivity {
private EditText ed = null;
private NumberFormat amountFormatter = null;
private boolean isUserInput = true;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.app_home_screen);
ed = (EditText)findViewById(R.id.main_amount_textfield);
amountFormatter = new DecimalFormat("##,##,###");
ed.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if(event.getAction() == KeyEvent.ACTION_DOWN)
return true;
String strippedAmount = ed.getText().toString().replace(",", "");
if(keyCode == KeyEvent.KEYCODE_DEL){
//delete pressed, strip number of comas and then delete least significant digit.
strippedAmount = strippedAmount.substring(0, strippedAmount.length() - 1);
int amountNumeral = 0;
try{
amountNumeral = Integer.parseInt(strippedAmount);
} catch(NumberFormatException e){
}
myObject.amount = amountNumeral;
isUserInput = false;
setFormattedAmount(amountNumeral,ed.getId());
}else if(keyCode == KeyEvent.KEYCODE_ENTER){
//enter pressed, save edits and resign keyboard
int amountNumeral = 0;
try{
amountNumeral = Integer.parseInt(strippedAmount);
} catch(NumberFormatException e){
}
myObject.amount = amountNumeral;
isUserInput = false;
setFormattedAmount(myObject.amount,ed.getId());
//save edits
save();
//resign keyboard..
InputMethodManager in = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
in.hideSoftInputFromWindow(AppHome.this.getCurrentFocus().getWindowToken(),InputMethodManager.HIDE_NOT_ALWAYS);
}
return true;
}
});
TextWatcher inputTextWatcher = new TextWatcher() {
public void afterTextChanged(Editable s) {
if(isUserInput == false){
//textWatcher is recursive. When editText value is changed from code textWatcher callback gets called. So this variable acts as a flag which tells whether change is user generated or not..Possibly buggy code..:(
isUserInput = true;
return;
}
String strippedAmount = ed.getText().toString().replace(",", "");
int amountNumeral = 0;
try{
amountNumeral = Integer.parseInt(strippedAmount);
} catch(NumberFormatException e){
}
isUserInput = false;
setFormattedAmount(amountNumeral,ed.getId());
}
public void beforeTextChanged(CharSequence s, int start, int count, int after){
}
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
};
ed.addTextChangedListener(inputTextWatcher);
}//end of onCreate...
public void setFormattedAmount(Integer amount, Integer inputBoxId){
double amountValue = 0;
String textString =null;
TextView amountInputBox = (TextView) findViewById(inputBoxId);
amountValue = Double.parseDouble(Integer.toString(amount));
textString = amountFormatter.format(amountValue).toString();
amountInputBox.setText(textString);
}
}
我知道这是一个很大的问题,但我正在研究同样的问题2天。我是Android的新手,仍然不能相信没有简单的方法来处理textEdit数据(我在iphone上轻松完成了相同的工作)。谢谢大家
编辑:使用输入过滤器后
InputFilter filter = new InputFilter() {
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
String strippedAmount = dest.toString() + source;
strippedAmount = strippedAmount.replace(",", "");
int amountNumeral = 0;
try{
amountNumeral = Integer.parseInt(strippedAmount);
} catch(NumberFormatException e){
}
return amountFormatter.format(amountNumeral).toString();
}
};
ed.setFilters(new InputFilter[]{filter});
当应用程序启动时,我将1,234放在editText
上myObject.amount = 1234;
ed.setText(amountFormatter.format(myObject.amount).toString());
然后当用户点击editText时,弹出键盘,并说用户输入数字6
我得到:61234我想: 12346
答案 0 :(得分:8)
好吧,经过多次敲击,我找到了一个解决光标位置问题的工作......我不知道这是不是正确的方法,但我让它工作了..
TextWatcher inputTextWatcher = new TextWatcher() {
public void afterTextChanged(Editable s) {
if(isUserInput == false){
//textWatcher is recursive. When editText value is changed from code textWatcher callback gets called. So this variable acts as a flag which tells whether change is user generated or not..Possibly buggy code..:(
isUserInput = true;
ed.setSelection(ed.getText().length());
return;
}
String strippedAmount = ed.getText().toString().replace(",", "");
int amountNumeral = 0;
try{
amountNumeral = Integer.parseInt(strippedAmount);
} catch(NumberFormatException e){
}
isUserInput = false;
setFormattedAmount(amountNumeral,ed.getId());
}
public void beforeTextChanged(CharSequence s, int start, int count, int after){
}
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
};
ed.addTextChangedListener(inputTextWatcher);
ed.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int length = ed.getText().length();
ed.setCursorVisible(true);
ed.setSelection(length);
}
});
ed.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if(event.getAction() == KeyEvent.ACTION_UP)
return true;
String strippedAmount = ed.getText().toString().replace(",", "");
if(keyCode == KeyEvent.KEYCODE_DEL){
//delete pressed, strip number of comas and then delete least significant digit.
strippedAmount = strippedAmount.substring(0, strippedAmount.length() - 1);
int amountNumeral = 0;
try{
amountNumeral = Integer.parseInt(strippedAmount);
} catch(NumberFormatException e){
}
isUserInput = false;
setFormattedAmount(amountNumeral,ed.getId());
return true;
}else if(keyCode == KeyEvent.KEYCODE_ENTER){
//enter pressed, save edits and resign keyboard
int amountNumeral = 0;
try{
amountNumeral = Integer.parseInt(strippedAmount);
} catch(NumberFormatException e){
}
isUserInput = false;
setFormattedAmount(amountNumeral,ed.getId());
//save edits
//resign keyboard..
InputMethodManager in = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
in.hideSoftInputFromWindow(AppHome.this.getCurrentFocus().getWindowToken(),InputMethodManager.HIDE_NOT_ALWAYS);
return true;
}
return false;
}
});
我所做的是在editText的onClick()上,我强行将光标放在当前EditText文本的末尾,当用户按下任何数字时我也做了同样的事情。希望它有所帮助。感谢所有试图提供帮助的人。
答案 1 :(得分:4)
对于Masked输入,您可以继承InputFilter
下面是一个示例InputFilter子类,它将所有小写字母大写:
/**
* This filter will capitalize all the lower case letters that are added
* through edits.
*/
public static class AllCaps implements InputFilter {
public CharSequence filter(CharSequence source, int start, int end,
Spanned dest, int dstart, int dend) {
for (int i = start; i < end; i++) {
if (Character.isLowerCase(source.charAt(i))) {
char[] v = new char[end - start];
TextUtils.getChars(source, start, end, v, 0);
String s = new String(v).toUpperCase();
if (source instanceof Spanned) {
SpannableString sp = new SpannableString(s);
TextUtils.copySpansFrom((Spanned) source,
start, end, null, sp, 0);
return sp;
} else {
return s;
}
}
}
return null; // keep original
}
}
答案 2 :(得分:1)
经过几个小时的工作后,我做了一个电话输入面罩。 对于istance,进入&#34; 123456&#34;它将其转换为&#34; +1(234)56&#34;。从任何位置删除任何符号后,光标移动到正确的位置,而不是开始或结束。
活动:
etPhone.addTextChangedListener(new PhoneWatcher(etPhone));
课堂上:
private class PhoneWatcher implements TextWatcher {
private static final String PHONE_MASK = "+# (###) ###-##-##";
private final char[] PHONE_MASK_ARRAY = PHONE_MASK.toCharArray();
private boolean isInTextChanged;
private boolean isInAfterTextChanged;
private EditText editText;
private int shiftCursor;
private String text;
private int cursor;
public PhoneWatcher(EditText editText) {
super();
this.editText = editText;
isInTextChanged = false;
isInAfterTextChanged = false;
}
@Override
public synchronized void beforeTextChanged(CharSequence s, int start, int count, int after) {
shiftCursor = after - count;
}
@Override
public synchronized void onTextChanged(CharSequence s, int start, int before, int count) {
if (!isInTextChanged) {
isInTextChanged = true;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
char symbol = s.charAt(i);
if (symbol >= '0' && symbol <= '9')
sb.append(symbol);
}
String digits = sb.toString();
sb.setLength(0);
int j = 0;
for (int i = 0; i < digits.length(); i++) {
char digit = digits.charAt(i);
while (j < PHONE_MASK_ARRAY.length) {
if (PHONE_MASK_ARRAY[j] == '#') {
sb.append(digit);
j++;
break;
} else {
sb.append(PHONE_MASK_ARRAY[j]);
j++;
}
}
}
cursor = editText.getSelectionStart();
text = sb.toString();
if (shiftCursor > 0) {
if (cursor > text.length())
cursor = text.length();
else {
while (cursor < PHONE_MASK_ARRAY.length && PHONE_MASK_ARRAY[cursor - 1] != '#') {
cursor++;
}
}
} else if (shiftCursor < 0) {
while (cursor > 0 && PHONE_MASK_ARRAY[cursor - 1] != '#') {
cursor--;
}
}
}
}
public synchronized void afterTextChanged(Editable s) {
if (!isInAfterTextChanged) {
isInAfterTextChanged = true;
editText.setText(text);
editText.setSelection(cursor);
isInTextChanged = false;
isInAfterTextChanged = false;
}
}
}