覆盖 getText 的 EditText
Override getText's EditText
我想覆盖 EditText 的 getText()
。
我收到这种字符串:"12,345,678"
我的目的是只删除逗号和 return Editable 但是当我的代码出现错误时。
public class AmountEditText extends EditText {
@Override
public Editable getText() {
Editable s = super.getText();
if(s!=null && s.length()>0) {
if (s.toString().contains(",")) {
return new SpannableStringBuilder(s.toString().replace(",", ""));
}
}
return s;
}
private TextWatcher watcher = 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) {
int position = getSelectionStart();
int nbCommaBefore;
int nbCommaAfter;
String str = s.toString();
String finalStr;
String formattedStr;
nbCommaBefore = str.length() - str.replace(",", "").length();
boolean containsDot = false;
if (str.contains(".")) {
containsDot = true;
formattedStr = str.split("\.")[0];
} else {
formattedStr = str;
}
if (!s.toString().isEmpty()) {
removeTextChangedListener(watcher);
formattedStr = formattedStr.replace(",", "");
formattedStr = formattedStr.replaceAll("(\d)(?=(\d{3})+$)", ",");
if (containsDot) {
if (str.split("\.").length != 1) {
finalStr = formattedStr + "." + str.split("\.")[1].replace(",", "");
} else {
finalStr = formattedStr + ".";
}
} else {
finalStr = formattedStr;
}
nbCommaAfter = finalStr.length() - finalStr.replace(",", "").length();
setText(finalStr);
if (position == str.length()){
setSelection(finalStr.length());
}
else if (position == 0)
{
setSelection(0);
}
else if (nbCommaBefore < nbCommaAfter){
setSelection(position + 1);
}
else if (nbCommaAfter < nbCommaBefore){
setSelection(position - 1);
}
else{
setSelection(position);
}
addTextChangedListener(watcher);
}
}
@Override
public void afterTextChanged(Editable s) {
}
};
public AmountEditText(Context context) {
this(context, null);
}
public AmountEditText(Context context, AttributeSet attrs) {
super(context, attrs);
addTextChangedListener(watcher);
}
public AmountEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
addTextChangedListener(watcher);
}
}
E/MessageQueue-JNI: Exception in MessageQueue callback:
handleReceiveCallback E/MessageQueue-JNI:
java.lang.IndexOutOfBoundsException: setSpan (0 ... 5) ends beyond
length 4
at android.text.SpannableStringBuilder.checkRange(SpannableStringBuilder.java:1265)
at android.text.SpannableStringBuilder.setSpan(SpannableStringBuilder.java:684)
at android.text.SpannableStringBuilder.setSpan(SpannableStringBuilder.java:677)
at android.widget.SpellChecker$SpellParser.setRangeSpan(SpellChecker.java:532)
at android.widget.SpellChecker$SpellParser.parse(SpellChecker.java:515)
at android.widget.SpellChecker.spellCheck(SpellChecker.java:242)
at android.widget.Editor.updateSpellCheckSpans(Editor.java:679)
at android.widget.Editor.sendOnTextChanged(Editor.java:1249)
at android.widget.TextView.sendOnTextChanged(TextView.java:8191)
at android.widget.TextView.setText(TextView.java:4483)
at android.widget.TextView.setText(TextView.java:4337)
at android.widget.EditText.setText(EditText.java:89)
at android.widget.TextView.setText(TextView.java:4312)
at org.newtonproject.newpay.widgetlib.AmountEditText.onTextChanged(AmountEditText.java:74)
我想明确指出错误不是来自我的 onTextChanged
因为没有 getText() override
一切正常
EDIT :用户可以输入数字,我会附加一些逗号以格式化数字。但是当我覆盖 getText()
时,我想以这种方式删除这些逗号,我不必每次都过滤 getText()
的 return
试试这个,它会对你有所帮助
editText.addTextChangedListener(new TextWatcher() {
boolean isEdiging;
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
public void afterTextChanged(Editable s) {
if (isEdiging) return;
isEdiging = true;
String str = s.toString().replaceAll("[^\d]", "");
double s1 = 0;
try {
s1 = Double.parseDouble(str);
} catch (NumberFormatException e) {
e.printStackTrace();
}
NumberFormat nf2 = NumberFormat.getInstance(Locale.ENGLISH);
((DecimalFormat) nf2).applyPattern("###,###.###");
s.replace(0, s.length(), nf2.format(s1));
if (s.toString().equals("0")) {
editText.setText("");
}
isEdiging = false;
}
});
好的,我调试了一下,发现问题出在那一行
if (position == str.length()){
setSelection(finalStr.length());
}
lenght()
超出集合选择范围,因为它基于 0
只需更改您的代码即可正常工作
if (position == str.length()){
setSelection(finalStr.length() - 1);
}
如果需要,这里有完整的代码(我使用的是 AppCompatEditText,但它是一样的):
public class AmountEditText extends android.support.v7.widget.AppCompatEditText {
@Override
public Editable getText() {
Editable s = super.getText();
if(s!=null && s.length()>0) {
if (s.toString().contains(",")) {
return new SpannableStringBuilder(s.toString().replace(",", ""));
}
}
return s;
}
private TextWatcher watcher = 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) {
int position = getSelectionStart();
int nbCommaBefore;
int nbCommaAfter;
String str = s.toString();
String finalStr;
String formattedStr;
nbCommaBefore = str.length() - str.replace(",", "").length();
boolean containsDot = false;
if (str.contains(".")) {
containsDot = true;
formattedStr = str.split("\.")[0];
} else {
formattedStr = str;
}
if (!s.toString().isEmpty()) {
removeTextChangedListener(watcher);
formattedStr = formattedStr.replace(",", "");
formattedStr = formattedStr.replaceAll("(\d)(?=(\d{3})+$)", ",");
if (containsDot) {
if (str.split("\.").length != 1) {
finalStr = formattedStr + "." + str.split("\.")[1].replace(",", "");
} else {
finalStr = formattedStr + ".";
}
} else {
finalStr = formattedStr;
}
nbCommaAfter = finalStr.length() - finalStr.replace(",", "").length();
setText(finalStr);
if (position == str.length()){
setSelection(finalStr.length() - 1);
}
else if (position == 0)
{
setSelection(0);
}
else if (nbCommaBefore < nbCommaAfter){
setSelection(position + 1);
}
else if (nbCommaAfter < nbCommaBefore){
setSelection(position - 1);
}
else{
setSelection(position);
}
addTextChangedListener(watcher);
}
}
@Override
public void afterTextChanged(Editable s) {
}
};
public AmountEditText(Context context) {
this(context, null);
}
public AmountEditText(Context context, AttributeSet attrs) {
super(context, attrs);
addTextChangedListener(watcher);
}
public AmountEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
addTextChangedListener(watcher);
}
}
如果有帮助请告诉我!
在您的情况下,您不能同时覆盖 getText()
和调整大小并使用 TextWatcher
。
查看下面的 android 源代码,您就会知道为什么
SpannableStringBuilder.java
public void setSpan(Object what, int start, int end, int flags) {
setSpan(true, what, start, end, flags, true/*enforceParagraph*/);
}
private void setSpan(boolean send, Object what, int start, int end, int flags,
boolean enforceParagraph) {
checkRange("setSpan", start, end);
}
private void checkRange(final String operation, int start, int end) {
...
int len = length();
if (start > len || end > len) {
throw new IndexOutOfBoundsException(operation + " " +
region(start, end) + " ends beyond length " + len); // here is you exception
}
}
public int length() {
return mText.length - mGapLength;
}
SpellChecker.java
private void setRangeSpan(Editable editable, int start, int end) {
...
editable.setSpan(mRange, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
public void parse(int start, int end) {
...
if (parseEnd > start) {
setRangeSpan((Editable) mTextView.getText(), start, parseEnd); // I think the error happened from here, they use your getText() function here and receive shorter string, but the start, parseEnd still stick with original string
parse();
}
}
解决方案 .
您可以简单地定义一个新函数,例如 getBeautifulText()
。
根据您问题的要求:
The user can enter number, I will append some commas in order to
format the number. But when I override getText() I want to delete
these commas
我相信您可以使用涉及 DecimalFormat
:
的更简单的解决方案
class Formatter {
private final DecimalFormat f = new DecimalFormat(",###");
private final DecimalFormat o = new DecimalFormat("#");
String withCommas(String in) {
try {
return withCommas(Long.parseLong(in));
} catch (NumberFormatException e) {
e.printStackTrace();
return withCommas(Long.MIN_VALUE);
}
}
String withCommas(long in) {
return f.format(in);
}
Number stripCommas(String in) {
try {
return f.parse(in);
} catch (ParseException e) {
return Long.MIN_VALUE;
}
}
String stripCommasAsString(String in) {
return o.format(stripCommas(in));
}
}
给出:
final long num = 12345678L;
final Formatter f = new Formatter();
assertEquals("12,345,678", f.withCommas("12345678"));
assertEquals("12,345,678", f.withCommas(num));
assertEquals(num, f.stripCommas("12,345,678");
assertEquals("12345678", f.stripCommasAsString("12,345,678"));
我想覆盖 EditText 的 getText()
。
我收到这种字符串:"12,345,678"
我的目的是只删除逗号和 return Editable 但是当我的代码出现错误时。
public class AmountEditText extends EditText {
@Override
public Editable getText() {
Editable s = super.getText();
if(s!=null && s.length()>0) {
if (s.toString().contains(",")) {
return new SpannableStringBuilder(s.toString().replace(",", ""));
}
}
return s;
}
private TextWatcher watcher = 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) {
int position = getSelectionStart();
int nbCommaBefore;
int nbCommaAfter;
String str = s.toString();
String finalStr;
String formattedStr;
nbCommaBefore = str.length() - str.replace(",", "").length();
boolean containsDot = false;
if (str.contains(".")) {
containsDot = true;
formattedStr = str.split("\.")[0];
} else {
formattedStr = str;
}
if (!s.toString().isEmpty()) {
removeTextChangedListener(watcher);
formattedStr = formattedStr.replace(",", "");
formattedStr = formattedStr.replaceAll("(\d)(?=(\d{3})+$)", ",");
if (containsDot) {
if (str.split("\.").length != 1) {
finalStr = formattedStr + "." + str.split("\.")[1].replace(",", "");
} else {
finalStr = formattedStr + ".";
}
} else {
finalStr = formattedStr;
}
nbCommaAfter = finalStr.length() - finalStr.replace(",", "").length();
setText(finalStr);
if (position == str.length()){
setSelection(finalStr.length());
}
else if (position == 0)
{
setSelection(0);
}
else if (nbCommaBefore < nbCommaAfter){
setSelection(position + 1);
}
else if (nbCommaAfter < nbCommaBefore){
setSelection(position - 1);
}
else{
setSelection(position);
}
addTextChangedListener(watcher);
}
}
@Override
public void afterTextChanged(Editable s) {
}
};
public AmountEditText(Context context) {
this(context, null);
}
public AmountEditText(Context context, AttributeSet attrs) {
super(context, attrs);
addTextChangedListener(watcher);
}
public AmountEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
addTextChangedListener(watcher);
}
}
E/MessageQueue-JNI: Exception in MessageQueue callback: handleReceiveCallback E/MessageQueue-JNI: java.lang.IndexOutOfBoundsException: setSpan (0 ... 5) ends beyond length 4 at android.text.SpannableStringBuilder.checkRange(SpannableStringBuilder.java:1265) at android.text.SpannableStringBuilder.setSpan(SpannableStringBuilder.java:684) at android.text.SpannableStringBuilder.setSpan(SpannableStringBuilder.java:677) at android.widget.SpellChecker$SpellParser.setRangeSpan(SpellChecker.java:532) at android.widget.SpellChecker$SpellParser.parse(SpellChecker.java:515) at android.widget.SpellChecker.spellCheck(SpellChecker.java:242) at android.widget.Editor.updateSpellCheckSpans(Editor.java:679) at android.widget.Editor.sendOnTextChanged(Editor.java:1249) at android.widget.TextView.sendOnTextChanged(TextView.java:8191) at android.widget.TextView.setText(TextView.java:4483) at android.widget.TextView.setText(TextView.java:4337) at android.widget.EditText.setText(EditText.java:89) at android.widget.TextView.setText(TextView.java:4312) at org.newtonproject.newpay.widgetlib.AmountEditText.onTextChanged(AmountEditText.java:74)
我想明确指出错误不是来自我的 onTextChanged
因为没有 getText() override
EDIT :用户可以输入数字,我会附加一些逗号以格式化数字。但是当我覆盖 getText()
时,我想以这种方式删除这些逗号,我不必每次都过滤 getText()
的 return
试试这个,它会对你有所帮助
editText.addTextChangedListener(new TextWatcher() {
boolean isEdiging;
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
public void afterTextChanged(Editable s) {
if (isEdiging) return;
isEdiging = true;
String str = s.toString().replaceAll("[^\d]", "");
double s1 = 0;
try {
s1 = Double.parseDouble(str);
} catch (NumberFormatException e) {
e.printStackTrace();
}
NumberFormat nf2 = NumberFormat.getInstance(Locale.ENGLISH);
((DecimalFormat) nf2).applyPattern("###,###.###");
s.replace(0, s.length(), nf2.format(s1));
if (s.toString().equals("0")) {
editText.setText("");
}
isEdiging = false;
}
});
好的,我调试了一下,发现问题出在那一行
if (position == str.length()){
setSelection(finalStr.length());
}
lenght()
超出集合选择范围,因为它基于 0
只需更改您的代码即可正常工作
if (position == str.length()){
setSelection(finalStr.length() - 1);
}
如果需要,这里有完整的代码(我使用的是 AppCompatEditText,但它是一样的):
public class AmountEditText extends android.support.v7.widget.AppCompatEditText {
@Override
public Editable getText() {
Editable s = super.getText();
if(s!=null && s.length()>0) {
if (s.toString().contains(",")) {
return new SpannableStringBuilder(s.toString().replace(",", ""));
}
}
return s;
}
private TextWatcher watcher = 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) {
int position = getSelectionStart();
int nbCommaBefore;
int nbCommaAfter;
String str = s.toString();
String finalStr;
String formattedStr;
nbCommaBefore = str.length() - str.replace(",", "").length();
boolean containsDot = false;
if (str.contains(".")) {
containsDot = true;
formattedStr = str.split("\.")[0];
} else {
formattedStr = str;
}
if (!s.toString().isEmpty()) {
removeTextChangedListener(watcher);
formattedStr = formattedStr.replace(",", "");
formattedStr = formattedStr.replaceAll("(\d)(?=(\d{3})+$)", ",");
if (containsDot) {
if (str.split("\.").length != 1) {
finalStr = formattedStr + "." + str.split("\.")[1].replace(",", "");
} else {
finalStr = formattedStr + ".";
}
} else {
finalStr = formattedStr;
}
nbCommaAfter = finalStr.length() - finalStr.replace(",", "").length();
setText(finalStr);
if (position == str.length()){
setSelection(finalStr.length() - 1);
}
else if (position == 0)
{
setSelection(0);
}
else if (nbCommaBefore < nbCommaAfter){
setSelection(position + 1);
}
else if (nbCommaAfter < nbCommaBefore){
setSelection(position - 1);
}
else{
setSelection(position);
}
addTextChangedListener(watcher);
}
}
@Override
public void afterTextChanged(Editable s) {
}
};
public AmountEditText(Context context) {
this(context, null);
}
public AmountEditText(Context context, AttributeSet attrs) {
super(context, attrs);
addTextChangedListener(watcher);
}
public AmountEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
addTextChangedListener(watcher);
}
}
如果有帮助请告诉我!
在您的情况下,您不能同时覆盖 getText()
和调整大小并使用 TextWatcher
。
查看下面的 android 源代码,您就会知道为什么
SpannableStringBuilder.java
public void setSpan(Object what, int start, int end, int flags) {
setSpan(true, what, start, end, flags, true/*enforceParagraph*/);
}
private void setSpan(boolean send, Object what, int start, int end, int flags,
boolean enforceParagraph) {
checkRange("setSpan", start, end);
}
private void checkRange(final String operation, int start, int end) {
...
int len = length();
if (start > len || end > len) {
throw new IndexOutOfBoundsException(operation + " " +
region(start, end) + " ends beyond length " + len); // here is you exception
}
}
public int length() {
return mText.length - mGapLength;
}
SpellChecker.java
private void setRangeSpan(Editable editable, int start, int end) {
...
editable.setSpan(mRange, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
public void parse(int start, int end) {
...
if (parseEnd > start) {
setRangeSpan((Editable) mTextView.getText(), start, parseEnd); // I think the error happened from here, they use your getText() function here and receive shorter string, but the start, parseEnd still stick with original string
parse();
}
}
解决方案 .
您可以简单地定义一个新函数,例如 getBeautifulText()
。
根据您问题的要求:
The user can enter number, I will append some commas in order to format the number. But when I override getText() I want to delete these commas
我相信您可以使用涉及 DecimalFormat
:
class Formatter {
private final DecimalFormat f = new DecimalFormat(",###");
private final DecimalFormat o = new DecimalFormat("#");
String withCommas(String in) {
try {
return withCommas(Long.parseLong(in));
} catch (NumberFormatException e) {
e.printStackTrace();
return withCommas(Long.MIN_VALUE);
}
}
String withCommas(long in) {
return f.format(in);
}
Number stripCommas(String in) {
try {
return f.parse(in);
} catch (ParseException e) {
return Long.MIN_VALUE;
}
}
String stripCommasAsString(String in) {
return o.format(stripCommas(in));
}
}
给出:
final long num = 12345678L;
final Formatter f = new Formatter();
assertEquals("12,345,678", f.withCommas("12345678"));
assertEquals("12,345,678", f.withCommas(num));
assertEquals(num, f.stripCommas("12,345,678");
assertEquals("12345678", f.stripCommasAsString("12,345,678"));