runtime TextWatcher control - android

I have 4 edittext and i would like to implement a TextWatcher with a control value.
Et1Burro.addTextChangedListener(new TextWatcher() {
public void afterTextChanged(Editable value) {
// you can call or do what you want with your EditText here
Dvalue = GetEditValue(value);
double et4tot = 0, et2fibra = 0, et3zucc = 0;
// et1burro + et2fibra = et4tot
// et1burro + et2fibra + et3zucc = 100
try {
et4tot = Double.parseDouble(Et4Tot.getText().toString());
} catch (NumberFormatException e) { e.printStackTrace(); }
try {
et2fibra = Double.parseDouble(Et2Fibra.getText().toString());
} catch (NumberFormatException e) { e.printStackTrace(); }
try {
et3zucc = Double.parseDouble(Et3Zucc.getText().toString());
} catch (NumberFormatException e) { e.printStackTrace(); }
if ((Dvalue < 1) || (Dvalue > 100) || ((Dvalue + et2fibra) != et4tot ) || ((Dvalue + et2fibra + et3zucc) != 100 ))
{
//segnala errore
Et1Burro.setTextColor(getActivity().getBaseContext().getResources().getColor(R.color.Red));
}else
Et1Burro.setTextColor(getActivity().getBaseContext().getResources().getColor(R.color.Black));
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
public void onTextChanged(CharSequence s, int start, int before, int count) {}
});
i would like to have a red number if the range number is wrong and a black number if is correct.
I think is better to implement a AsynckTask for control the number or not?
for example the 4 edittext value are:
A,B,C,D
the relation for correct value are:
A+B = D
A+B+C = 100
C = 100 - D
correct example value are A=35, B=35, C=30, D=70
but if in teh first edit (A) the user insert the first caracter ex 35 the program respond with RED value because the other value are 0, and when the user compile all the edittext with the value 35,35,30,70 the anly value that are Black is the last.
I hope to be clear...

Because you are updating only one edit text's color
What i would suggest is,
Set default color to RED for all edit texts
Write a function for your "control value" logic. Call this function only when there are values in all edit texts.
Update all the editbox's color to black if the values entered are passing your control logic. Else you have to set it to RED

Related

Trigger Multiple Times TextEdit onTextChanged

My basic code is works, but then i confuse about trigger, when edit some editText. When editText is edit or change..
my reference's :
TextWatcher events are being fired multiple times
My input type Xml is number, and i try it. other method is use ignore, and still got same result, stuck. number|textNoSuggestions
Compare to this, android edittext onchange listener my code still make in sense..
The strange result from this :
Events of TextWatcher are being called twice
.
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
editModelArrayList.get(position).setEditTextValueCrt(holder.editTextCrt.getText().toString());
if (mToggle) {
if (mToggle2) {
Log.d(TAG, "onTextChanged: HIT KEY" + mToggle);
}
mToggle2 = !mToggle2;
}
mToggle = !mToggle;
}
The first code will only fires/trigger for 1 times, compare with 2nd codes will result multiple trigger at once :
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
editModelArrayList.get(position).setEditTextValueCrt(holder.editTextCrt.getText().toString());
if (mToggle) {
if (mToggle2) {
Log.d(TAG, "onTextChanged: HIT KEY" + mToggle);
try {
Integer val = Integer.valueOf(holder.editTextSeq.getText().toString());
if exist data previously, so never replace in seq only
}
catch (Exception e){
//get all data, if empty > set 1, else set : check all data, count data +1
List<Integer> listQtySeq;
listQtySeq = new ArrayList<Integer>();
for (int j = 0; j < CustomeAdapter.editModelArrayList.size(); j++){
String nilaiSeq = editModelArrayList.get(j).getEditTextValueSeq();
nilaiSeq = checkNull(nilaiSeq);
if (Integer.parseInt(nilaiSeq) > 0) {
listQtySeq.add(Integer.parseInt(nilaiSeq));
}
}
Log.d(TAG, "afterTextChanged: size llistq: "+listQtySeq.size());
if(listQtySeq.size()<1){
editModelArrayList.get(position).setEditTextValueSeq("1");
}
else{
Integer totSize = listQtySeq.size()+1;
Log.d(TAG, "afterTextChanged: size newZise: "+totSize.toString());
editModelArrayList.get(position).setEditTextValueSeq(totSize.toString());
}
Log.d(TAG, "onTextChanged: error ~" + e);
}
}
mToggle2 = !mToggle2;
}
mToggle = !mToggle;
}
I want to use that method to execute only once, with some customize code. My question is why my second code invoke multiple trigger, i didn't use loop, or else,,
Thanks for help.

How to change text color while typing special word

on MultpuAutocompletTexView while Typing I want to make some special word that is start with # want to make that word alone with some colour, how can I do this any help.
so when ever I type with # that word should be in colour text.
like this image
Use TextWatcher with Spanable text, and every time you need to check the last enter word, means the 0 index of last word is #, if YES then apply Spanable for EditText.
please have a look on below code.
define this variable on public level
int beforeChangeSize = 0, afterChangeSize = 0, cusrsorPos = 0, posOflastSpace = 0;
String lastcursorSubString = "";
#Override
public void afterTextChanged(Editable editable) {
if (afterChangeSize > beforeChangeSize) {
cusrsorPos = 0;
posOflastSpace = 0;
lastcursorSubString = "";
cusrsorPos = txt_search.getSelectionStart();
String sudString = txt_search.getText().toString().substring(0, cusrsorPos);
posOflastSpace = sudString.lastIndexOf(" ");
posOflastSpace = (posOflastSpace == -1) ? 0 : posOflastSpace;
lastcursorSubString = sudString.substring(posOflastSpace, cusrsorPos).trim();
if ((lastcursorSubString.length() > 1 &&(lastcursorSubString.charAt(0) == '#') {
textlable.setText(""+lastcursorSubString);
// txt_search.getText().replace(posOflastSpace+1, cusrsorPos, Html.fromHtml("<font color=#FE642E>" + lastcursorSubString + "</font>"));
// txt_search.showDropDown();
editable.setSpan(new ForegroundColorSpan(Color.RED),
posOflastSpace+1,
cusrsorPos,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
}
you should use combination of textWatcher and spannable text
use text watcher to see what user is typing and use spannable text to give special color or format to part of your text in textView or EditText
good tutorial for spannable text :
https://medium.com/google-developers/spantastic-text-styling-with-spans-17b0c16b4568
and documentation for text watcher here :
https://developer.android.com/reference/android/widget/TextView.html#addTextChangedListener(android.text.TextWatcher)
You can add your own TextChangedListener and implement onTextChanged method
myAutoTxtView.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence text, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence text, int start, int before, int count) {
if (text.charAt(start) == '#') {
//change color
}
}
#Override
public void afterTextChanged(Editable s) {
}
});
this code to change color - use it in on text change listener like above (its kotlin you need to modify it to Java if you want to)
//get text
val str = editText.text.toString()
//get last word
val splitStr = str.trim { it <= ' ' }.split("\\s+".toRegex()).dropLastWhile {
it.isEmpty() }.toTypedArray()
val ColorWord = splitStr.last()
//get the sentence without the last word
val textButLast = str.substring(0, str.lastIndexOf(" "))
//change the last word color
val LastWord = "<font color='#EE0000'>$ColorWord</font>"
//put the last word with the sentence again
editText.setText(Html.fromHtml(textButLast + LastWord))

Prevent whitespace in a string after one is entered

I made a code where user can't enter first space in a string.
User is allowed to enter white space after min 2 characters.
I need to redefine my method so user enters white space once, and only once after the two or more characters. After that it should be prevented. How do I do that?
case UPDATE_NAME:
if (firstName.getText().toString().startsWith(" "))
firstName.setText(firstName.getText().toString().trim());
if (firstName.getText().toString().contains(" "))
firstName.setText(firstName.getText().toString().replace(" ", " "));
int indexOfSpace = firstName.getText().toString().lastIndexOf(" ");
if (indexOfSpace > 0) {
String beforeSpace = firstName.getText().toString().substring(0, indexOfSpace);
String[] splitted = beforeSpace.split(" ");
if (splitted != null && splitted.length > 0) {
if (splitted[splitted.length - 1].length() < 2)
firstName.setText(firstName.getText().toString().trim());
}
}
Use a regex pattern. I made one that should match your requirements.
\S{2}\S*\s\S*\n
Explanation:
\S{2} two non whitespace
\S* n non whitespace
\s a whitespace
\S* n non whitespace
\n newline (i only added that for regexr, you may not need it)
Alternate way:
Iterate over String.charAt(int), return false if there is a whitespace in the first two chars, count all whitespaces, return false if n > 1.
This method should meet your requirements:
private static boolean isValidFirstName(String firstName) {
if (firstName != null && !firstName.startsWith(" ")) {
int numberOfSpaces = firstName.length() - firstName.replace(" ", "").length();
if (firstName.length() < 2 || numberOfSpaces <= 1) {
return true;
}
}
return false;
}
What you need to do is use a TextWatcher
public class CustomWatcher implements TextWatcher {
private String myText;
private int count = 0;
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after){
myText= s;
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void afterTextChanged(Editable s) {
//check if there is a space in the first 2 characters, if so, sets the string to the previous before the space
if(s.length() < 3 && s.contains(" "))
s= myText;
//if the length is higher than 2, and the count is higher than 0 (1 space added already), puts the string back if a space is entered
else if(s.contains(" ") && count > 0)
s= myText;
//If none of the above is verified and you enter a space, increase count so the previous if statement can do its job
else if(s.contains(" "))
count++;
}
}
And then, set it to your EditText
mTargetEditText.addTextChangedListener(new CustomWatcher());
You can control your editText(I assume) with a TextWatcher, you would only need to check inside afterTextChanged() if length is <2 and else if the string contains the char " ".

Output string with decimal format limited to 2 dp

Stuck on this which im sure there is an easy solution to, just cannot work it out!!
I have tried decmialformat, numberformat, string.format() etc and nothing works. .
code below, i want to calculation to just show the output limited to 2 decimal places. Have spent the last 2 hours trying various methods all of which causes the app to crash when run...
Output = (Output1 / (1 -(Output2/100)))
String OutputString = String.valueOf(Output);
Num.setText(OutputString);
Try this :
String OutputString = String.format("%.2f", Output);
Num.setText(OutputString);
String.format() to make sure you only get 2 decimal places in your output.
please try this:
double Output = (Output1 / (1 -(Output2/100d)))
Num.setText(String.format("%.2f",Output));
Hope this solves your problem.
Best regards
If you want to Limit the number of Digits before and after the 'decimal_point' then you can use my solution.
private class DecimalNumberFormatTextWatcher implements TextWatcher{
int pos;
int digitsBeforeDecimal = 6;
int digitsAfterDecimal = 2;
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
if(s.length() > 2)
pos = start;
else {
pos = start + 2;
}
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void afterTextChanged(Editable s) {
mEdittext.removeTextChangedListener(this);
String text = s.toString();
if(text!= null && !text.equals("")){
if(!text.contains("$")){ //if it does not contains $
text = "$"+text;
} else {
if (text.indexOf("$") > 0) { //user entered value before $
text = s.delete(0, text.indexOf("$")).toString();
}else {
if(!text.contains(".")){ // not a fractional value
if(text.length() > digitsBeforeDecimal+1) { //cannot be more than 6 digits
text = s.delete(pos, pos+1).toString();
}
} else { //a fractional value
if(text.indexOf(".") - text.indexOf("$") > digitsBeforeDecimal+1){ //non fractional part cannot be more than 6
text = s.delete(pos,pos+1).toString();
}
if((text.length() - text.indexOf(".")) > digitsAfterDecimal+1) { //fractinal part cannot be more than 2 digits
text = s.delete(text.indexOf(".") + 2, text.length() - 1).toString();
}
}
}
}
}
mEdittext.setText(text);
mEdittext.setSelection(pos);
mEdittext.addTextChangedListener(this);
}
}
mEdittext.addTextChangedListener(new DecimalNumberFormatTextWatcher());
This also adds a currency sign as soon as the user types the value.
HOPE THIS HELPS ANYONE.

Optimizing my syntax highlighter

I've decided I have to write my own syntax highlighter. So far it's working but it's realtime (you type, it highlights) and it's slow.
I'll try to explain how it works. Each time the user types something into the EditText it runs the highlighter (via TextWatcher). The highlighter searches through the text until it finds the beginning of a word and then searches until it finds the end of the same word. Once it finds a word it searches through an array of keywords, if it finds a match it sets a spannable at that location. It keeps looping until it reaches the end of the document.
Again, it works so far (just trying out this idea before I continue with this method), but it's so slow. Some times it can take over a second just to go through a few lines. It slows down how fast the text appears in the EditText. - I also set where the highlighter starts after text is entered at the last position where the user typed so it doesnt have to go through the whole doc each time, it helps a little but not much.
Here's the basic of my EditText:
public class CodeView extends EditText {
private int mTxtChangeStart;
String mStructures[] = this.getResources().getStringArray(R.array.structures);
public CodeView(Context context, AttributeSet attrs) {
super(context, attrs);
addTextChangedListener(inputTextWatcher);
...
}
TextWatcher inputTextWatcher = new TextWatcher() {
#Override
public void afterTextChanged(Editable s) {
syntaxHighlight();
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
//Set where we should start highlighting
mTxtChangeStart = start;
}
#Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
}
};
private void syntaxHighlight() {
//Time how long it takes for debugging
long syntime = System.currentTimeMillis();
Log.d("", "Start Syntax Highlight");
//Get the position where to start searching for words
int strt = mTxtChangeStart;
//Get the editable text
Editable txt = getText();
//Back up the starting position to the nearest space
try {
for(;;) {
if(strt <= 0) break;
char c = txt.charAt(strt);
if(c != ' ' && c != '\t' && c != '\n' && c != '\r') {
strt--;
} else {
break;
}
}
} catch (IndexOutOfBoundsException e) {
Log.e("", "Find start position failed: " + e.getMessage());
}
//Just seeing how long this part took
long findStartPosTime = System.currentTimeMillis();
Log.d("", "Find starting position took " + String.valueOf(System.currentTimeMillis() - findStartPosTime) + " milliseconds");
//the 'end of a word' position
int fin = strt;
//Get the total length of the search text
int totalLength = txt.length();
//Start finding words
//This loop is to find the first character of a word
//It loops until the current character isnt a space, tab, linebreak etc.
while(fin < totalLength && strt < totalLength) {
for(;;) {
//Not sure why I added these two lines - not needed here
//fin++;
//if(fin >= totalLength) { break; } //We're at the end of the document
//Check if there is a space at the first character.
try {
for(;;) { //Loop until we find a useable character
char c = txt.charAt(strt);
if (c == ' ' || c == '\t' || c == '\n' || c == '\r'){
strt++; //Go to the next character if there is a space
} else {
break; //Found a character (not a space, tab or linebreak) - break the loop
}
}
}catch(IndexOutOfBoundsException e) {
Log.e("", e.getMessage());
break;
}
//Make sure fin isnt less than strt
if(strt > fin) { fin = strt; }
//Now we search for the end of the word
//Loop until we find a space at the end of a word
try {
for(;;) {
char c = txt.charAt(fin);
if(c != ' ' && c != '\t' && c != '\n' && c != '\r') {
fin++; //Didn't find whitespace here, keep looking
} else {
break; //Now we found whitespace, end of a word
}
}
break;
} catch (IndexOutOfBoundsException e) {
//If this happens it should mean it just reached the end of the document.
Log.e("", "End of doc? : " + e.getMessage());
break;
}
}
Log.d("", "It took " + String.valueOf(System.currentTimeMillis() - findStartPosTime) + " milliseconds to find a word");
//Make sure fin isnt less that start, again
if(strt > fin) { fin = strt; }
//Debug time, how long it took to find a word
long matchTime = System.currentTimeMillis();
//Found a word, see if it matches a word in our string[]
try {
for(String mStruct : mStructures) {
if(String.valueOf(txt.subSequence(strt, fin)).equals(mStruct)) {
//highlight
Spannable s = (Spannable) txt;
s.setSpan(new ForegroundColorSpan(Color.RED), strt, fin, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
//Can someone explain why this is still setting the spannable to the main editable???
//It should be set to txt right???
break;
} else {
/*Spannable s = (Spannable) txt;
s.setSpan(new ForegroundColorSpan(Color.BLACK), strt, fin, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
txt.removeSpan(s);*/
}
}
}catch (IndexOutOfBoundsException e) {
e.printStackTrace();
Log.e("", "word match error: " + e.getMessage());
}
//Finally set strt to fin and start again!
strt = fin;
Log.d("", "match a word time " + String.valueOf(System.currentTimeMillis() - matchTime) + " milliseconds");
}//end main while loop
Log.d("", "Syntax Highlight Finished in " + (System.currentTimeMillis() - syntime) + " milliseconds");
mTextChanged = false;
}
}
"structures" resource (php.xml)
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="structures">
<item>if</item>
<item>else</item>
<item>else if</item>
<item>while</item>
<item>do-while</item>
<item>for</item>
<item>foreach</item>
<item>break</item>
<item>continue</item>
<item>switch</item>
<item>declare</item>
<item>return</item>
<item>require</item>
<item>include</item>
<item>require_once</item>
<item>include_once</item>
<item>goto</item>
</string-array>
</resources>
Anyone have any suggestions how to make this search faster? I know I have a lot of loops but I'm not sure how else to do it.
Thanks a lot!
Can you split the string on the delimiters you have there rather than looking at each character? That would speed it up some. (String.split())

Categories

Resources