I'm developing a simple app that flips the word in a sentence. I need it to have three ways of doing that depending on mode the user chooses by enabling RadioButtons. So I use RadioGroup as parent layout to be able to enable one RadioButton at a time.
I can achieve this simply by switching their IDs.
modeGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
switch (checkedId){
case R.id.rb_mode_1:
String[] nowTyping = input.getText().toString().split(" ");
ArrayList<String> wordArray = new ArrayList<>();
for (String word : nowTyping){
wordArray.add(0, word);
}
String invertedSentence = TextUtils.join(" ", wordArray);
output.setText(invertedSentence);
break;
//And so...
}
}
});
Now as the output text is printed as the user is typing, I use TextWatcher to get what user is typing directly be shown into a textView. Now I'm unable to change mode because the code that flips the words is actually called from onTextChanged() method that the class implements.
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
String[] nowTyping = input.getText().toString().split(" ");
ArrayList<String> wordArray = new ArrayList<>();
for (String word : nowTyping){
wordArray.add(0, word);
}
String invertedSentence = TextUtils.join(" ", wordArray);
output.setText(invertedSentence);
}
My question is, how can I achieve my need when also using TextWatcher? Actually I can either change mode without being able to get texts by output in real time or have texts be output without being able to change mode.
I solved this using getCheckedRadioButtonId() method of RadioGroup directly inside onTextChanged() method of TextWatcher like below:
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (modeGroup.getCheckedRadioButtonId() == R.id.rb_mode_1) {
String[] nowTyping = input.getText().toString().split(" ");
ArrayList<String> wordArray = new ArrayList<>();
for (String word : nowTyping) {
wordArray.add(0, word);
}
String invertedSentence = TextUtils.join(" ", wordArray);
output.setText(invertedSentence);
}
else if (modeGroup.getCheckedRadioButtonId() == R.id.rb_mode_2){
//Do mode 2 stuffs...
}
....
}
Sometimes we just don't dig enough before asking other to do for us.
Related
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 have provided an AutoCompleteTextView to show suggestions to the user. Based on the item selected by the user, I am getting the ID of the item and using it in data base side. Now my problem is to force the user to make selection only from AutoCompleteTextView (i.e. user should not enter his own text). It is a client requirement. How to do this?
Here's a pretty straightforward solution:
You can create a variable to store the selected value by setting setOnItemClickListener in your AutoCompleteTextView. Then you can null that value whenever a user types in the field by adding a TextWatcher to it. Finally, you can validate your variable is not null before continuing.
String my_var; //keep track!
AutoCompleteTextView tv = (AutoCompleteTextView) layout.findViewById(R.id.tv);
tv.setAdapter(my_adapter);
tv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
my_var = my_adapter.getItem(position).toString();
}
});
/**
* Unset the var whenever the user types. Validation will
* then fail. This is how we enforce selecting from the list.
*/
tv.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) {
my_var = null;
}
#Override
public void afterTextChanged(Editable s) {}
});
I happened to need such a requirement for a project I am working on, and I though I'll share you guys the way I implemented the required.
I added a on focus change listener for the auto-complete text view and checked when the user has focus changed focus from the auto-complete, and handled the situation straight forward.
autoTextViewCountry.setOnFocusChangeListener(new View.OnFocusChangeListener() {
#Override
public void onFocusChange(View view, boolean b) {
if(!b) {
// on focus off
String str = autoTextViewCountry.getText().toString();
ListAdapter listAdapter = autoTextViewCountry.getAdapter();
for(int i = 0; i < listAdapter.getCount(); i++) {
String temp = listAdapter.getItem(i).toString();
if(str.compareTo(temp) == 0) {
return;
}
}
autoTextViewCountry.setText("");
}
}
});
So my implementation is: if the typed text doesn't exist in the array adapter then on focus changed empty the text view, and later on when continuing to next stage of say registration, check if this text view is empty or not.
Hope this approach helps somebody.
Happy coding.
NiceAutoCompleteTextView will give you the ability to check whether a selection was made from the drop-down popup, by invoking isSelectionFromPopup()
Just add this property to your AutoCompleteTextView.
android:focusable="false"
My Code looks like:
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/menu"
style="#style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Mode">
<AutoCompleteTextView
android:id="#+id/mode"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusable="false"
/>
</com.google.android.material.textfield.TextInputLayout>
On Java Side:
AutoCompleteTextView mode = findViewById(R.id.mode);
final List<String> modeList = new ArrayList();
modeList.add("YEARLY");
modeList.add("HALF-YEARLY");
modeList.add("QUARTER-YEARLY");
modeList.add("MONTHLY");
mode.setAdapter(new ArrayAdapter(getApplicationContext(),R.layout.list_item,modeList));
To get the Text of AutoCompleteTextView:
mode.getText().toString()
Ok I assume you would like to limit the input of the user to the texts contained in the list of items listed in the suggest box.
For instance if you have:
One
Two
Three
then the user could only type for the first character "O" and "T".
And so on according to the text entered before.
To achieve this you can utilize the setFilters method of TextView:
editBox = (TextView) findViewById(R.id.editBox);
editBox.setFilters(getFilters());
editBox.addTextChangedListener(this);
editBox.setOnFocusChangeListener(this);
Additionally you would probably need the text change listener and focus listener to react and update the filtered list when a new character is entered ... plus to update the filter.
Here is an example of decimal number filter I have used on a project:
protected InputFilter[] getFilters()
{
InputFilter[] filters = new InputFilter[1];
filters[0] = new InputFilter()
{
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend)
{
// limit input to digits and decimal / thousand separator only
// in case thousand separator is pressed, change it to decimal
// separator instead
String output = "";
if (number.isFocused())
{
for (int i = start; i < end; i++)
{
char c = source.charAt(i);
if (isDecimalOrThousandSeparator(c))
{
output = output + Character.toString(decimalSeparator);
}
else if (Character.isDigit(c))
{
output = output + Character.toString(c);
}
}
return output == "" ? null : output;
}
return null;
}
};
return filters;
}
A simple solution would be to just check if the current input is one of the items in the adapter. You can do it like this:
val AutoCompleteTextView.isValid: Boolean
get() {
for (i in 0 until adapter.count) {
if (adapter.getItem(i) == text.toString()) {
return true
}
}
return false
}
here is the another solution for this proAutoCompleteTextView.Validator to ensure the valid values. Validator is invoked when edit text looses focus.
autoCompleteTextView.validator = object : AutoCompleteTextView.Validator {
override fun isValid(text: CharSequence?): Boolean {
return optionsList.contains(text.toString())
}
override fun fixText(invalidText: CharSequence?): CharSequence {
return ""
}
}
Where optionsList is list of valid values.
I was having the same requirement, so here is my implementation:
autoCompleteTextView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
autoCompleteTextView.showDropDown();
}
});
In the xml set focusable=false and focusableInTouchMode=false.
Happy coding
In order to have a non editable variation of the AutoCompleteTextView, you should disable user input in the AutoCompleteTextView. That can be achieved by setting android:inputType="none" on the AutoCompleteTextView.
I am fetching names from the webservices using xml parsing. I am using edittextbox for searching names. Now, When I type the first letter of the first name or last name, It perfectly retrieves and shows the names list.
But, when I type the first name and I left a space before typing the lastname, the names list displays nothing. But Actually, the related search results should display according to the typed first name.
The code I am using:
HashMap map = new HashMap();
map.put("Name",String.valueOf(XMLfuncts.getValue(e, "Name")));
mylist.add(map);
adapter = new SimpleAdapter(ViewList.this, mylist,R.layout.userdetails_row, new String[] { "Name",
"Moblie", "CompName" }, new int[] {
R.id.TextViewName, R.id.number,
R.id.compname });
searchname.addTextChangedListener(new TextWatcher() {
public void onTextChanged(CharSequence s, int start, int before,
int count) {
// onTextChanged
}
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// beforeTextChanged
}
public void afterTextChanged(Editable s) {
// afterTextChanged
adapter.getFilter().filter(s);
adapter.notifyDataSetChanged();
}
});
The thing which I need is the search results should remain active eventhough I type the space between firstname and lastname in the edittextbox.
map.put("Name",String.valueOf(XMLfuncts.getValue(e, "Name")));
Try by replacing this line as
String str = String.valueOf(XMLfuncts.getValue(e, "Name"));
str =str.trim(); // will remove space between names
map.put("Name",str);
Hope this will work..!
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 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.