Everytime Edittext onAfterTextChange method, i check if some special string(which comes from functionlist variable) is entered then change that string's special color. Code is below
for(String s:functionList)
{
final Pattern p = Pattern.compile(s);
final Matcher matcher = p.matcher(inputStr);
while(matcher.find())
{
//if(matcher.end() - matcher.start()== s.length())
inputStr.setSpan(new ForegroundColorSpan(Color.parseColor(highlightColor)),
matcher.start(), matcher.end(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
The reason why i am not using Html.FromHtml method is; it forces me to use setText method which changes cursor position and since my edittext is also changed from buttons(buttons call settext) not only softkeyboard, that settext method ruins cursor position since button changes sets cursor position to 0 EVEN IT IS NOT!!!! thus i cannot add something in the middle with softkeyboard(when i try to add, cursorposition is set always to 0). This is why i have to use spannable.
Anyway my problem is, for example one of my special text is "log".. when i input log it works fine(log), when append log with space character(log log) it works fine again but WHEN I REMOVE g from second log, the first log color is also gone!!!(log lo) which must not supposed to be happen. Think bold logs as it is colored...
Why is it happening?
If I understand correctly what you're attempting to do, you should try something like:
edit.addTextChangedListener(new TextWatcher()
{
#Override
public void onTextChanged(CharSequence s, int start, int before, int count)
{
Spannable inputStr = (Spannable)s;
for (String function : functionList)
{
for (ForegroundColorSpan old : inputStr.getSpans(start, inputStr.length(), ForegroundColorSpan.class))
inputStr.removeSpan(old);
final Pattern p = Pattern.compile(function);
final Matcher matcher = p.matcher(inputStr);
while (matcher.find())
inputStr.setSpan(new ForegroundColorSpan(Color.BLUE), matcher.start(), matcher.end(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
#Override
public void afterTextChanged(Editable s) { }
});
Related
Is there any easy way to add spaces before the start of Sentence in edittext. Suppose if I want to Type
"Hello my name is Zohan.
I am from kochi"
It should be displayed like
" Hello my name is Zohan.
"I am from kochi.
To be more specific , is there anyway to provide padding for the first line only in a multiline supported ediText ?
Obviously padding feature is not doing the task.
You can add TextChangedListener to your EditText , this will trigger when you add your first line to your EditText, also i added a boolean value and this will triggered only one time:
Add this boolean in your global scope : boolean isSpaceAdded=false;
mEdittextContent.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) {
if(!isSpaceAdded) {
if (mEdittextContent.getLineCount() > 1) {
mEdittextContent.removeTextChangedListener(this);
String editstring= mEdittextContent.getText().toString();
mEdittextContent.getText().clear();
mEdittextContent.setText(" "+editstring);
isSpaceAdded=true;
mEdittextContent.addTextChangedListener(this);
}
}
}
});
What is the point here :
You must remove TextChangedListener before change EditText's text. Screenshot :
Use LeadingMarginSpan
https://developer.android.com/reference/android/text/style/LeadingMarginSpan.Standard.html
public void setIndent(int length) {
//First remove the original indent(s)
for (LeadingMarginSpan span : getText().getSpans(0, getText().length(), LeadingMarginSpan.class)) {
getText().removeSpan(span);
}
mIndent = new LeadingMarginSpan.Standard(length, 0);
getText().setSpan(mIndent, 0, 0, 0);
}
String myString = editText.getText().toString();
myString = " " + myString;
editText.setText(myString);
This should work
One possibility would be to add some whitespaces at the beginning of the text of the EditText. Thererfore you would need to add an TextChangedListener like this:
yourEditText.addTextChangedListener(new TextWatcher(){
public void afterTextChanged(Editable s) {
String text = yourEditText.getText().toString();
//I'm adding four whitespaces in this example...
if (!text.substring(0,4).equals(" ") {
text = " " + text;
}
yourEditText.setText(text);
}
public void beforeTextChanged(CharSequence s, int start, int count, int after){}
public void onTextChanged(CharSequence s, int start, int before, int count){}
});
This might sound a little noob way of doing it but you can try adding some Space in the beginning of Edittext programmatically beforeTextChanged(), and when extracting the text out of Edittext, you can subString it to remove the spaces you add in the beginning
You can get all the lines in the textbox, append spaces to the lines needed, then set the text of te textbox to the text you updated.
I have to watch EditText in my App in such a way that if in EditText data is in 2 lines
then again I want to write in 3rd line then previous 2 line's data should get clear.
For this I am using following way to do
mTextWatcher = new TextWatcher() {
private int lines;
#Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
Log.v("", "inside ontextchnaged");
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
lines = getTotalLines(txtDataSource);
if (lines == 2) {
txtDataSource.removeTextChangedListener(mTextWatcher);
Log.v("", txtDataSource.getText().toString());
txtDataSource.setText("");
txtDataSource.addTextChangedListener(mTextWatcher);
}
}
#Override
public void afterTextChanged(Editable s) {
Log.v("", "inside aftertextchanged");
}
};
txtDataSource.addTextChangedListener(mTextWatcher);
and I am getting no of lines enter by the below code
private int getTotalLines(EditText editText) {
int lineNumber = 0;
String text = editText.getText().toString()
.substring(0, editText.getSelectionStart());
for (int i = 0; i < text.length(); i++) {
if (String.valueOf(text.charAt(i)).equalsIgnoreCase("\n")) {
lineNumber++;
}
}
return lineNumber;
}
So when i m getting 2 lines data in EditText then I am removing watcher from EditText
then clearing data of EditText and again I added watcher on EditText .
Every thing working fine but problem is after 2 lines when I start to wrote then it is not writing first character which I enter from Keypad it starts writing from second character input.
So after 2 lines when enter 2 characters then it didnt write first char which i enter it starts writing from second character.
Please help me to resolve this.
Thanks ....
Finally I solved my issue.
It may not be standard way to do, but I didn't find any other way to do this inside
beforeTextChanged()
I solved using the below code inside onTextChanged()
#Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
lines = getTotalLines(txtDataSource);
if (lines == 2 ) {
String frstChar = String.valueOf(s.toString().charAt(s.toString().length() - 1));
txtDataSource.removeTextChangedListener(mTextWatcher);
txtDataSource.setText("" + frstChar);
txtDataSource.setSelection(txtDataSource.getText().toString().length());
txtDataSource.addTextChangedListener(mTextWatcher);
}
}
and now in 3rd line first character is getting displayed in EditText.
I am sharing my way so that if someone else would face such issue they can solve by this way..
Thanks
Try to solve the problem when you edit from the middle of the word.
"setSelection" keeps forcing you to write at the end of the text.
I'm using a AutoCompleteTextView, the default behavior of the backspace button goes something like this.
Say i type "Ar", this gives me a suggestion "Argentina", i select "Argentina" from the drop down...The Text now becomes "Argentina ". But say i need to remove the last character, so I hit backspace on the keyboard, the AutcompleteTextView removes all the text till the point i typed (ie. the text now becomes "Ar" again).
How do i eliminate this behavior and let the text in the AutoComplete to behave normally?
At first I thought it was some kind of SpannableString so i called "clearSpans()" but it doesn't seem to work. Any pointers?
Thanks in advance. :)
I think you use the MultiAutoCompleteTextView which add the setTokenizer(new SpaceTokenizer()).
If you use
AutoCompleteTextView instead of MultiAutoCompleteTextView and remove the setTokenizer(...)
the problem will be gone.
I did not find any solution, but finally I figured out, this code worked for me:
editText.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
try {
// removing QwertyKeyListener.Replaced span
Editable text = editText.getText();
Object[] spans = text.getSpans(0, text.length(), Object.class);
if (spans != null) {
for (int i = spans.length - 1; i >= 0; i--) {
Object o = spans[i];
String desc = "" + o; // This is a hack, not a perfect solution, but works. "QwertyKeyListener.Replaced" is a private type
if (desc.indexOf("QwertyKeyListener$Replaced") != -1) {
text.removeSpan(o);
}
}
}
} catch (Throwable e) {
MyUtil.msgError(e);
}
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void afterTextChanged(Editable s) {
}
});
I have a situation where I would like the user to complete a sentence for me. For example, consider a EditText with a hint of "The last time I ". Normally, when a user clicks an EditText, the hint disappears, but I would like it to stay. Additionally, I would like the text to be permanent, so that it cannot be erased... leaving the user with only one option... complete the sentence.
The first part is fairly simple, just use the setText() method of EditText to place the hint. The difficult part is the latter. How can I have text in an EditText that the user cannot erase?
Well couldn't you do it in code? Some algorithim like, if the text is less than 16 characters (length of "The last time I ") then set the text to that. Therefore whenever they clicked it, if they tried to erase it, it would just go back to the default text.
Also, another idea..why don't you just make a TextView thats right edge aligns with the left edge of the EditText box, the user would never know that it was another box. This is acutally the best solution, if you don't want the text ever to be edited, just make it a TextView
Described problem can be solved using android.text.TextWatcher.
public class CompleteSentenceWathcher implements TextWatcher {
private final String initialText;
private int start;
private int after;
private int count;
public CompleteSentenceWathcher(String initialText) {
this.initialText = initialText;
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
this.start = start;
this.count = count;
this.after = after;
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void afterTextChanged(Editable s) {
if(start < initialText.length()) {
if(s.toString().startsWith(initialText)) {
return;
}
if(count >= 1 && after == 0) {
if(start+count+1 <= initialText.length()) {
s.replace(start, start+count, initialText.substring(start, start+count+1));
} else {
s.replace(start, start, initialText.substring(start, start+1));
}
} else if(count == 0 && after >= 1) {
s.delete(start, start+after);
}
}
}
}
Create an instance of EditText and add the TextWatcher.
EditText editText = new EditText(this);
editText.setText("I love");
editText.addTextChangedListener(new CompleteSentenceWathcher(editText.getText().toString()));
I've implemented this with an InputFilter, where _PERMANENT_HINT_TEXT is the text at the end of the EditText that I don't want the user to be able to modify. I recommend adding a color span to it, so that it is grayed out to hopefully look like a hint/disabled section of text. This should hopefully improve the UX as they should automatically assume it is unmodifiable, and not just wonder why some part of the EditText (that they usually can completely change) isn't "working". This approach allowed the text to be set after
the InputFilter was set on the EditText, which was a requirement for me since I used this on an EditTextPreference.
To be clear, I needed the permanent text to exist at the end of the EditText, instead of the beginning, but that should be symmetrical to my implementation.
new InputFilter() {
#Override
public CharSequence filter(CharSequence source, int source_start, int source_end,
Spanned destination, int destination_start, int destination_end) {
final int protected_text_start = (TextUtils.isEmpty(destination)? source.length() : destination.length()) - _PERMANENT_HINT_TEXT.length();
// Allows input into unprotected region
if (source_start + destination_start - source_end < protected_text_start)
return null;
// Prevents deletion of protected region
else if (TextUtils.isEmpty(source))
return destination.subSequence(destination_start, destination_end);
// Ignores insertion into protected region
else
return "";
}
}
use EditText.setFilters(new InputFilters[] { /* InputFilter goes here */ }; to add it to the desired EditText.
Just checking for the length wouldn't be adequate... I could type "This is a really long text I put into the box" and it would accept it even though it doesn't begin with "The last time I" string.
Personally, I would probably go for the prevention method suggested of using a TextView over that of a check on the way out. But if you're going to validate it afterwards, you'd actually need to check the beginning of the returned string.
I have a TextWatcher set on an EditText that changes the input type after a user types a number followed by a space.
If the user types two numbers the input type switches and accepts the next character, but if the user types only one number and presses space the input type still changes but it won't accept the first character the user tries to input.
I've tested this on Froyo and 1.6, it only happens on Froyo, 1.6 works like it should.
Here's the code:
TextWatcher watcher = 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) {
// Parsed text holder is a class that just parses the EditText and pulls out various parts.
ParsedTextHolder th = parseTextHolder(s);
String newText = "";
Boolean setTextKeyListener = false;
String tGetTextString = mQuery.getText().toString();
if (!th.pFullMatch.equals("")) {
if (th.pFullMatch.length() == 2) {
mQuery.setKeyListener(new
TextKeyListener(TextKeyListener.Capitalize.SENTENCES, true));
newText = tGetTextString + " for ";
setTextKeyListener = true;
}
}
if (setTextKeyListener) {
Log.i("setTextKeyListener", "true");
if (mQuery.getKeyListener().getClass() != TextKeyListener.class) {
mQuery.setKeyListener(new TextKeyListener(TextKeyListener.Capitalize.SENTENCES, true));
} else {
Log.d("setTextKeyListener", "skipped. already was text.");
}
if (!newText.equals("")) {
int position = newText.length();
String ttext = newText;
newText = "";
mQuery.setText(ttext, TextView.BufferType.EDITABLE);
mQuery.setText(ttext);
Editable text = mQuery.getEditableText();
Log.w("setting selectiont to text: ", text.toString());
Log.w("setting selectiont to position: ", Integer.toString(position));
Selection.setSelection(text, position);
mQuery.setKeyListener(new TextKeyListener(TextKeyListener.Capitalize.SENTENCES, true));
}
}
}
};
Also, here's an APK if you want to see what the bug is like: http://endlesswhileloop.com/files/KeyboardBug.apk
Is mQuery the editText that is being watched? According to the javadocs, you shouldn't be making any changes to the text in your EditText in onTextChanged. All such changes should be made in afterTextChanged.
Generally, I've ended up examining the change in onTextChanged and then doing the work that results form the change in afterTextChanged. You might try that.