App freezes on autocomplete textChanged - java

I was able to get the first and last text of user input for AutoCompleteTextview but
My App freezes when i set the builder method on AutocompleteTextView textChanged method.
I appreciate any effort provided.
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if(s.length()>0) {
String selectedText = s.toString();
int end = selectedText.length()+start;
SpannableStringBuilder builder = new SpannableStringBuilder(selectedText);
builder.setSpan(android.graphics.Typeface.BOLD, start, end, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
Log.i("builderText", " "+builder);
autoCompleteTextView.setText(builder);
}
}

I had a similar issue and fixed it. I had an event called "OnLayoutChage" and added .SetSelection(searchText.Text.Length, searchText.Text.Length); to fix the issue.
"searchText" is AutoCompleteTextView(it is a kind of EditText type)
public void OnLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
searchText.DropDownAnchor = Resource.Id.appbar;
searchText.DropDownWidth = ViewGroup.LayoutParams.MatchParent;
.......
searchText.SetSelection(searchText.Text.Length, searchText.Text.Length);
}

The issue is that you are trying to get the index of a character on a possible empty string. That's why you get -1 here
String startText = autoCompleteTextView.getText().toString();
int start = startText.indexOf(0);
int end = startText.indexOf(1);
You might want to add that statement in a listener e.g. autoCompleteTextView.addTextChangedListener() and handle it there where the actual text changes occur.

Related

Min & Max Input values on Android Studio [duplicate]

This question already has answers here:
Is there a way to define a min and max value for EditText in Android?
(29 answers)
Closed 11 months ago.
I am creating an app that calculates the the users marks. How do I go forward, I'm trying to limit the user's input value to between min=0 and max=100?
I've got 3 inputs that I want to limit.
EditText a = (EditText) findViewById(R.id.Assignment1);
EditText b = (EditText) findViewById(R.id.Assignment2);
EditText c = (EditText) findViewById(R.id.Assignment3);
Tried using the following but only works when I execute my function.
public void YearMark(View v)
{
EditText a = (EditText) findViewById(R.id.Assignment1);
a.setFilters(new InputFilter[]{ new InputFilterMinMax("0", "100")});
As #JAY_Panchal mentioned, you can use an InputFilter:
public class RangeInputFilter implements InputFilter {
private final int min, max;
public RangeInputFilter(int min, int max) {
boolean rightOrder = min <= max;
this.min = rightOrder ? min : max;
this.max = rightOrder ? max : min;
}
#Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dStart, int dEnd) {
try {
String sourceStr = source.toString();
String destStr = dest.toString();
String result = destStr.substring(0, dStart) + sourceStr.substring(start, end) + destStr.substring(dEnd);
int input = Integer.parseInt(result);
if (min <= input && input <= max) return null;
} catch (NumberFormatException ignored) { }
return "";
}
}
When a user changes the content of an EditText, you can use an InputFilter to decide what actually changes in the EditText.
Returning null means that the input is accepted.
Returning something else (in this case "") means that source should be replaced with that (in this case, we want dest to stay as it is and thus have an empty source).
To assign your filter:
RangeInputFilter filter = new RangeInputFilter(0, 100);
InputFilter[] filters = new InputFilter[] {filter};
editText1.setFilters(filters);
editText2.setFilters(filters);
editText3.setFilters(filters);
Add this textwatcher for all three edittext a,b and c:
a.addTextChangedListener(new TextWatcher() {
#Override
public void afterTextChanged(Editable s) {
}
#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 strTest = editText1235.getText().toString().trim();
if (!strTest.equals("")) {
float no = Float.parseFloat(strTest);
if (no > 100) {
a.setText(null);
Toast.makeText(this, "enter a value less than 100", Toast.LENGTH_SHORT).show();
}
}
}
});
Also set input type of these text fields as number so that user cannot enter a negative sign,ie, any value less than 0.
android:inputType="number"
While submitting the details also check if the field is not empty like below:
if (a.getText().toString().trim().length() <=0 ||b.getText().toString().trim().length() <=0 ||c.getText().toString().trim().length() <= 0){
Toast.makeText(this, "Value cannot be empty", Toast.LENGTH_SHORT).show();
}
I don't know your usecase, but you might also want to use a SeekBar.
A SeekBar is a slider - you can select a number by sliding. It is also very customizable.
The main advantage is that the user does not need to open the keyboard.

Add quotation mark programatically to EditText

I created an EditText where users can type a sentence in it. I would like to automatically add quotation marks to it at the start and end of the sentence.
For example, If a user type: Believe you can and you're halfway there., I would like it to show in the EditText as:
If there is an option to add an image of a quotation mark and to make sure that it moves with the length of the string it could also do the job.
I tried something like this but my app crashes:
et_Quote.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
et_Quote.setText( "\" " + s.toString() + "\" ");
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void afterTextChanged(Editable s) {
}
});
Thank you
Inside onTextChanged you are calling setText, which calls onTextChanged inside which you are calling setText and so on... locked in loop, UI thread hangs
Consider adding some flag preventing multiple onTextChanged calls in a row
et_Quote.addTextChangedListener(new TextWatcher() {
private boolean hold = false;
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if(hold) return;
hold = true;
et_Quote.setText( "\" " + s.toString() + "\"");
hold = false;
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void afterTextChanged(Editable s) {
}
});
Note that with every character entered into et_Quote you are adding " at the beginning and end of String, so there will be multiple " characters, two per every character entered. add some code for checking if first/last character is already a ", if yes then don't add it obviously
boolean isFirst = s.length() != 0 && s.charAt(0) == '"';
boolean isLast = s.length() != 0 && s.charAt(s.length() - 1) == '"';
String toSet = (isFirst ? "" : "\" ") + s.toString().trim() + (isLast ? "" : "\"");
trim() method removes unnecessary whitespaces at the beginning and end of String (you can't call it on CharSequence, thus toString() used in there
If you are using hard text you can try this out.
android:text='"Hello"'
If not then try this out.
InputFilter filter = new InputFilter() {
public CharSequence filter(CharSequence source, int start, int end,
Spanned dest, int dstart, int dend) {
char[] chars = {'\'','"'};
for (int i = start; i < end; i++) {
if (new String(chars).contains(String.valueOf(source.charAt(index))) {
return "";
}
}
return null;
}
};
edit.setFilters(new InputFilter[] { filter });

Remove span when text inside the span is changed in Android

Let´s say I make a comment like this:
Hi Andrea check this out..... In that comment I want to highlight Andrea, but whenever I change the value of Andrea or when I delete one character of the word the span changes, the problem is that I´m using spannableString.setSpan(new StyleSpan(Typeface.BOLD), indexOfAt, highlightName.length() + indexOfAt, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE), which Spanned.SPAN_EXCLUSIVE_EXCLUSIVE accepts words in the middle and deletion of words, how can I remove the span when the user changes the word or delete a character of the word?
You need to watch for Text change on the edit text.
Assuming the EditText, you are using is named as commentEditText
commentEditText.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void afterTextChanged(Editable editable) {
String comment = editable.toString();
if (comment.indexOf('#') != -1) {
//Asumming the name string
String name = "Andrea";
int atIndex = comment.indexOf('#');
int endIndex = atIndex + name.length() + 1;
if (endIndex == -1 || endIndex > editable.length()) {
endIndex = editable.length();
}
if (comment.toLowerCase().contains(name.toLowerCase())) {
editable.setSpan(new StyleSpan(Typeface.BOLD), atIndex, endIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
} else {
StyleSpan[] spannable = editable.getSpans(atIndex, endIndex, StyleSpan.class);
if (spannable != null && spannable.length > 0) {
for (int i = 0; i < spannable.length; i++) {
editable.removeSpan(spannable[i]);
}
}
}
}
}
});
If you are using the SpannableString you have to recreate the whole thing on every change.
You can remove spans but you cannot change the source (the comment) because SpannableString source text is immutable.
I suggest on every change of the comment you create the SpannableString, look for names and tag them, then if the comment changes you repeat the same thing with a new SpannableString. There will be no performance problems because the comments are small in size.
If you want to have a mutable object you can use the SpannableStringBuilder but it's more complicated and there is no need for it.
You can try TextWatcher for this, simply add TextWatcher to the textview you want to achieve above and in on
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
//Do some magic here
}
Now whenever user types or deletes any character you will get a callback in this method upon receiving that you can reset your span.

Making EditText accept a range of values without post validation [duplicate]

This question already has answers here:
Is there a way to define a min and max value for EditText in Android?
(29 answers)
Closed 3 years ago.
Is there a way to only allow numbers x through y to be entered in a EditText dynamically?
I.E don't even allow a number below x or above y to be entered?
For example x = 1 y = 12.
Of course i could solve this in Java after the user hit submit with the invalid numbers and prompt them to enter again. It's a time waster though.
Something like android:digits="01234..." but being able to specify n-th fields.
e.g
A range going from 1 to 12
The user should not get confused since they are entering a month number.
I am already using android:maxLength="2" but i need finer control.
It's a bit crude (given that I wrote it quickly) but could do something like this. I would remove the onClick method and create an OnFocusChangeListener and put the code in there.
Also from what it looks like you want something that checks Input as it's being entered and I don't really know if that's possible for a set range let alone that it'll probably cause the app to lag. As suggested by others, validation after Input is the logical route.
public void ValidateInputClick(View view) {
int Min = 1;
int Max = 12;
final TextInputLayout EditTextIP = (TextInputLayout) findViewById(R.id.layoutInput);
String str = EditTextIP.getEditText().getText().toString();
if (str.equals("") || str.contains("\n")) {
EditTextIP.setError("Cannot be blank");
EditTextIP.setErrorEnabled(true);
}
else {
int inputToInt = Integer.parseInt(str);
if (inputToInt >= Min && inputToInt <= Max) {
//Show number
Snackbar.make(view, str, Snackbar.LENGTH_SHORT).show();
EditTextIP.setErrorEnabled(false);
} else {
//Clear text
EditTextIP.getEditText().setText("");
//Show Error
EditTextIP.setError("Number must be between 1-12");
EditTextIP.setErrorEnabled(true);
}
}
}
XML:
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/layoutInput">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/editText1"
android:hint="Please enter a number between 1 and 12"
android:maxLength="2"
android:onClick="ValidateInputClick"/>
</android.support.design.widget.TextInputLayout>
No need to do anything in xml.
Find EditText in code:
int minValue = 1;
int maxValue = 12;
EditText input = (EditText) findViewById(R.id.txtInput);
input.setInputType(InputType.TYPE_CLASS_NUMBER);
input.setFilters(new InputFilter[]
{
new InputFilterMinMax(minValue, maxValue),
new InputFilter.LengthFilter(String.valueOf(maxValue).length())
});
input.setKeyListener(DigitsKeyListener.getInstance("0123456789"));
Code for InputFilterMinMax:
public class InputFilterMinMax implements InputFilter {
private int min, max;
public InputFilterMinMax(int min, int max) {
this.min = min;
this.max = max;
}
#Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
try {
int input = Integer.parseInt(dest.toString() + source.toString());
if (isInRange(min, max, input))
return null;
} catch (NumberFormatException nfe) {
nfe.printStackTrace();
}
return "";
}
private boolean isInRange(int a, int b, int c) {
return b > a ? c >= a && c <= b : c >= b && c <= a;
}
}
Hope will help you!
I suggest that you still go for validation after Input. This is simply
logical, if you put yourself in End-User position. The user will try
to tap "99", yet you do not allow second digit to be more than 5. Are
you planning to somehow edit they soft-keyboard to only display
certain numbers in keyboard? That's waaay more confusing and time
consuming. Same would be with writting WARNING / INSTRUCTION messages
uppon user trying to write invalid number (= in this case you are anyway doing validation in background.
Check this SO answer for accessing certain digits in int:
SO: Accessing digits in int
And uppon entry just check for the 2nd digit, hence you allow for the first one to be from 1-9 (which is all).
if(secondDigit > 5){
// Warn the user of incorrect input
}
you can use Textwatcher for this.
please look at below code. In onTextChanged you can get which character is entered and count of Character entered.
TextWatcher textwatcher = getMandatoryTextWatcher(editText);
String text = editText.getText().toString();//At this point String text is not empty.
editText.addTextChangedListener(textwatcher);
public TextWatcher getMandatoryTextWatcher(final EditText editText) {
TextWatcher textwatcher = new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
//To change body of implemented methods use File | Settings | File Templates.
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
//To change body of implemented methods use File | Settings | File Templates.
}
#Override
public void afterTextChanged(Editable s) {
try {
//The first time this is called(the first softkey backspace press),
//text is empty. This causes a weird issue where the character that
//was just removed by pressing the backspace, reappears again.
//This is only the first time.
String text = editText.getText().toString();
if (text.length() <= 0) {
editText.setError(errorMandatory);
} else if (text.length() > 0) {
editText.setError(null);
} else {
editText.setError(errorMelding);
}
} catch (NumberFormatException nfe) {
editText.setError(errorMeldingTijdensParsen);
}
}
};
return textwatcher;
}
you can use something like this.
Hope this help you.
If your range is short and you don't need double numbers , I recommend you to use spinner for selecting numbers.

How to dynamically change the text size in Android

I want to implement a function,
EditText user when entering text, you can make changes in accordance with the set font size,
Such as Google Docs of Office,
Now I found a way to SpannableString, but read some examples seem unable to reach my needs
int index = input.getSelectionEnd();
SpannableString spann = new SpannableString(show_input);
AbsoluteSizeSpan word_size = new AbsoluteSizeSpan(18,true);
spann.setSpan(word_size, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
input.getText().insert(index, spann);
So is there any way to provide it?
Looks like you want to change size of selected text:
int start = editText.getSelectionStart();
int end = editText.getSelectionEnd();
Spannable text=(Spannable)editText.getText();
text.setSpan(new AbsoluteSizeSpan(NEW_TEXT_SIZE, true), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
editText.setText(text);
Use AbsoluteSizeSpan to change for actual size or RelativeSizeSpan for proportional size.
I trird to add TextWatcher(),
input =(EditText)findViewById(R.id.Input_EditText);
input.addTextChangedListener(new TextWatcher()
{
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)
{
int index = input.getSelectionEnd();
String nowstr;
if(index==0)
{
//do nothing
}
else
{
nowstr = s.toString();
char nowstr_array[] = nowstr.toCharArray();
show_input = String.valueOf(nowstr_array[index-1]);
SpannableStringBuilder spann = new SpannableStringBuilder(show_input);
AbsoluteSizeSpan word_size = new AbsoluteSizeSpan(40,true);
spann.setSpan(word_size, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
input.getText().insert(index, spann);
}
}
});
But this program will crash...
then,I try to do
Toast.makeText(MainActivity.this, spann, Toast.LENGTH_SHORT).show();
//input.getText().insert(index, spann);
But doing so can be displayed...
That is why?

Categories