java.lang.IndexOutOfBoundsException: setSpan (118 ... 119) ends beyond length 118 - java

I searched different questions but found nothing specific about my problem. I am changing text color by selecting color and works successfully however when I start deleting my edit text after typing a color text I get this error.
myedittext.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) {
spannableString.setSpan(new ForegroundColorSpan(Color.parseColor(txtColor)), start, start+1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
#Override
public void afterTextChanged(Editable s) {
}
});
}
I get the following error
java.lang.IndexOutOfBoundsException: setSpan (118 ... 119) ends beyond length 118
at android.text.SpannableStringBuilder.checkRange(SpannableStringBuilder.java:1309)
at android.text.SpannableStringBuilder.setSpan(SpannableStringBuilder.java:680)
at android.text.SpannableStringBuilder.setSpan(SpannableStringBuilder.java:672)
at com.apps.primalnotes.Fragments.EditorFragment$16.onTextChanged(EditorFragment.java:842)
at android.widget.TextView.sendOnTextChanged(TextView.java:10611)
at android.widget.TextView.handleTextChanged(TextView.java:10715)
at android.widget.TextView$ChangeWatcher.onTextChanged(TextView.java:14057)
I am writing in two colors now like this
now when i save it. it saves in pink color only and shows me like this
but now when i save it again without any changes it save in the colors i wrote it

The onTextChanged method is invoked to tell you that within CharSequence s, number of character count beginning at start have just replaced old text that had length before.
What is happening is that when user presses backspace, start is at the upper limit of your charsequence i.e. If you had seven character before, start is 6 which is the same as the last element. You are doing start+1 which is always a number out of index range.
myedittext.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) {
if(start < s.length() - 1 || count > before){
spannableString.setSpan(new ForegroundColorSpan(Color.parseColor(txtColor)), start, start+1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
#Override
public void afterTextChanged(Editable s) {
}
});
}
Didn't get to try that code but it should work. It's just to show you an idea of what you are doing wrong and what you should be doing.

When you delete text from the end of the string, the onTextChanged() method will be invoked with values representing the fact that the string is now shorter. It looks like you've written your code to always assume that the length will be longer; you're coloring in the just-typed character. But if you delete a character instead, you probably don't want to do this.
You could add a check to make sure that count is greater than before, this at the very least will indicate that text was added to the string.
if (count > before) {
spannableString.setSpan(...);
}

Related

Detect and change only "hello" text font-family from editText

I have an editText box and when user writes "hello" I want only change "hello" font-family change to italic but others text font-family stay same only change "hello"
String detectText, text;
detectText = "hello";
text = title.getText().toString();
detectText.
Could you please help me?
As someone said, you need a text watcher to be able to make changes when the text is changed. You also need spans to be able to style parts of the text. Here's a way to do it:
editText.addTextChangedListener(new TextWatcher() {
private static final String KEYWORD = "hello";
#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 s) {
// Remove previous spans.
for (StyleSpan span : s.getSpans(0, s.length(), StyleSpan.class)) {
s.removeSpan(span);
}
// Add new spans for every occurrence of the keyword.
int i = 0;
while (i != -1) {
i = text.toString().indexOf(KEYWORD, i);
if (i != -1) {
s.setSpan(new StyleSpan(Typeface.ITALIC), i, i + KEYWORD.length(),
Spannable.SPAN_INCLUSIVE_INCLUSIVE);
i += KEYWORD.length();
}
}
}
});
The text watcher has three methods called at different times of the editing, but it's only safe to make changes to the text in afterTextChanged. There, all previous style spans are removed then the text is scanned to add new ones.
Note that performance might be a problem if you intend to turn this into something a lot more complex, like a syntax highlighter. Right now all spans get readded everytime the user changes a single character.

Caused by: java.lang.IndexOutOfBoundsException on AutocompleteTextView [duplicate]

This question already has answers here:
App freezes on autocomplete textChanged
(2 answers)
Closed 6 years ago.
I get this error when i try to get the position of first and last character typed by a user in an AutoCompleteTextView.
I would appreciate any help provided.
When i add a textChangeListener i still get the error
java.lang.IndexOutOfBoundsException: setSpan (0 ... -1) has end before start
This is my codes below:
final AutoCompleteTextView autoCompleteTextView = (AutoCompleteTextView) findViewById(R.id.autocompleteView);
autoCompleteTextView.setAdapter(autoComplete);
autoCompleteTextView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
//my statements
}
});
autoCompleteTextView.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) {
//int start = startText.indexOf(0);
String startText = autoCompleteTextView.getText().toString();
int end = startText.indexOf(1);
SpannableStringBuilder builder = new SpannableStringBuilder(startText);
// set foreground color (text color) - optional, you may not want to change the text color too
builder.setSpan(new ForegroundColorSpan(Color.RED), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
// set background color
builder.setSpan(new BackgroundColorSpan(Color.YELLOW), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
// set result to AutoCompleteTextView
autoCompleteTextView.setText(builder);
}
#Override
public void afterTextChanged(Editable s) {
}
});
Error Log
01-31 16:02:37.418 20357-20357/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.lawerh.jonathan.partygoer, PID: 20357
java.lang.IndexOutOfBoundsException: setSpan (0 ... -1) has end before start
at android.text.SpannableStringBuilder.checkRange(SpannableStringBuilder.java:1101)
at android.text.SpannableStringBuilder.setSpan(SpannableStringBuilder.java:680)
at android.text.SpannableStringBuilder.setSpan(SpannableStringBuilder.java:673)
at com.lawerh.jonathan.partygoer.ui.MapActivity$8.onTextChanged(MapActivity.java:328)
at android.widget.TextView.sendOnTextChanged(TextView.java:8320)
at android.widget.TextView.handleTextChanged(TextView.java:8385)
at android.widget.TextView$ChangeWatcher.onTextChanged(TextView.java:10531)
at android.text.SpannableStringBuilder.sendTextChanged(SpannableStringBuilder.java:1051)
at android.text.SpannableStringBuilder.replace(SpannableStringBuilder.java:572)
at android.text.SpannableStringBuilder.replace(SpannableStringBuilder.java:503)
at android.text.SpannableStringBuilder.replace(SpannableStringBuilder.java:502)
at android.view.inputmethod.BaseInputConnection.replaceText(BaseInputConnection.java:693)
at android.view.inputmethod.BaseInputConnection.setComposingText(BaseInputConnection.java:453)
at com.android.internal.view.IInputConnectionWrapper.executeMessage(IInputConnectionWrapper.java:340)
at com.android.internal.view.IInputConnectionWrapper$MyHandler.handleMessage(IInputConnectionWrapper.java:78)
at android.os.Handler.dispatchMessage(Handler.java:111)
at android.os.Looper.loop(Looper.java:207)
at android.app.ActivityThread.main(ActivityThread.java:5728)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:789)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:679)
int end = int end = startText.indexOf(1);
Is returning -1 because the number 1 isn't being found in the string. Then when you use end in the setSpan call, you are passing (0,-1). Double check that your startText contains a 1 and it may be that you just need to put the 1 in quotes, like this:
int end = int end = startText.indexOf("1");
Problem is in int end = startText.indexOf(1); line of your code. First of all indexOf() function take character as an argument but you are passing 1 (integer) , and indexOf() function is returning -1 and when you are setting span builder.setSpan(new ForegroundColorSpan(Color.RED), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); then end value is -1, which throws
IndexOutOfBoundsException

EditText must have at least 10 characters? [duplicate]

This question already has an answer here:
EditText Minimum Length & Launch New Activity
(1 answer)
Closed 8 years ago.
I am a new developer on Android and Java. How can I make at least 10 characters in EditText ? Also, when the user enter a value less than 10, the application send an error message on screen. How can I do these ? [ edittext > = 10 ]
Use something like this:
EditText et = (EditText) findViewById(YOUR_EDITTEXT);
String s = et.getText().toString();
if(s.length() <= 10){
et.setError("Must exceed 10 characters!");
} else {
// ...
}
You can do that in several ways, but you can try this way:
if (myEditText.getText().length() < minLength) {
//Your message to there is no enough caracters
} else {
//Your action if it is satisfied.
}
You can set minLenght to 10, or whatever, or simply ask if value is less than 10.
I hope that you get idea from this.
You can use text watcher to check the user input and decide what to do inside
EditText editText = new EditText(this);
editText.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 s) {
}
});
Yo can validate your TextView and if it doesn't fit your requirements, use myTextView.setError(String) to show an error.
If not you will have to implement myTextView.addTextChangedListener(...) and do things manually.
Hope it helps.

Android virtual keyboard event

I'm trying to implement iPhone like PIN-code authorization with 4 EditText blocks like this:
I'm using TextWatcher to check if field was changed so I can jump between blocks.
Here is the code:
#Override
public void afterTextChanged(Editable s) {
if (del && index > 0) {
pin[index - 1].requestFocus();
}
else if ( ! del && ind < 3) {
pin[index + 1].requestFocus();
}
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
del = count != 0;
}
Everything works fine except when block is empty and DEL/BACKSPACE is pressed, I want to go back to previous block and clear its' value.
This is where TextWatcher fails me since no change was made in empty block it doesn't do anything.
I have tried using keyEventListener but it only catches events on emulator not on actual device via virtual keyboard.
Can anyone suggest an idea of how can I catch DEL event or any other way to implement this?
Maybe you can check if the field is empty before and after change? Don't know if any other key press can leave the field empty and so you can say, back was pressed and jump to previous field. Ok this is not a real technical solution, but just a different way of viewing the problem.
I found a workaround for this issue. This is probably not the best solution, but it works for me.
Aside from TextWatcher I've added InputFilter to blocks
#Override
public CharSequence filter(CharSequence source, int start, int end,
Spanned dest, int dstart, int dend) {
if ( end == 0 && ind > 0 && dest.length() == 0 ) {
pin[ind - 1].requestFocus();
}
return null;
}
I also think it's a better idea to port the rest of the code from TextWatcher to InputFilter

Filter Input in Real-Time?

I have an EditText (accepts 0-9) with a listener. I want to grab input as it's entered, apply a calculation, and display it in the same EditText box.
The box initially displays $0.00. When the user inputs a 2, I want to grab that from the box, parse it to remove the $ and decimal, convert it to an int... divide it by 100 and put a $ in front of it. After setText, it should display $0.02. If they then press 5, I'll grab it, parse it, end up with 25, do the math and it should display $0.25, etc.
I don't know if this is the best way, I'm open to new ideas. Here is my current code:
mEditPrice.addTextChangedListener(new TextWatcher(){
DecimalFormat dec = new DecimalFormat("0.00");
#Override
public void afterTextChanged(Editable arg0) {
}
#Override
public void beforeTextChanged(CharSequence s, int start,
int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
String userInput = mEditPrice.getText().toString().replaceAll("[^\\d]", "");
int userInputInt = Integer.parseInt(userInput);
mEditPrice.setText("$"+dec.format(userInputInt / 100));
}
There's a few issues to deal with here before you can achieve the kind of functionality you desire.
Whenever you deal with a TextWatcher you need to be careful when setting the text of the EditText object being watched. The reason for this is that every time you call setText on it, it will trigger the watcher again, causing your code to go into an infinite loop.
To prevent this, you should set the value of text you want to set into a variable outside of the onTextChanged method. When entering the method, check against this variable and only perform your processing code if the value is different from the CharSequence.
The integer variable userInputInt, when divided by 100, will be equal to zero.
This should be changed to a double to produce values like 0.02 etc.
After those changes we can get the EditText to show $0.02 after entering a 2. But because we have set the value of the EditText in code, the next entry into the EditText will be added to the beginning of the text. Then if we enter a '5' we get $50.02.
To overcome this, the last thing we need to do is set the position of the EditText to the end of the string, using the set position method.
Here's the final solution:
private String value;
mEditPrice.addTextChangedListener(new TextWatcher(){
DecimalFormat dec = new DecimalFormat("0.00");
#Override
public void afterTextChanged(Editable arg0) {
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (!s.toString().equals(value)){
String userInput = mEditPrice.getText().toString().replaceAll("[^\\d]", "");
double userInputDouble = Double.parseDouble(userInput);
value = ("$"+dec.format(userInputDouble / 100));
mEditPrice.setText(value);
mEditPrice.setSelection(value.length());
}
}
});

Categories