Retain edit text cursor position using data binding in android - android

I have created a getter a setter for my building name and wish change the string to replace any characters that does not match with the regex expression. However in doing so, every time I enter an invalid character the edit text cursor/selection position changes to the beginning of the text. Hoe do I avoid this from happening?
private String buildingname="";
#Bindable
public String getBuildingname() {
return this.buildingname;
}
public void setBuildingname(String buildingname) {
if(!this.buildingname.equals(buildingname)) {
this.buildingname = buildingname.replaceAll(alphanumericregex,"");
this.pcr.notifyChange(this, com.tomtom.sangrahit.BR.buildingname);
}
}

You can use setSelection of editText AFTER you are setting new text
int position = myEditText.getSelectionStart();
myEditText.setText(myNewText);
myEditText.setSelection(position);

Related

Two-way data-binding infinite loop

I have a list of items. In each item's row I have 2 EditTexts side-by-side. EditText-2 depends on EditText-1's value. This list is bound with data-binding values in HashMap<String, ItemValues>
For Example:
Total _____1000____
Item A __1__ __200__
Item B __1__ __200__
Item C __1__ __200__
Item D __2__ __400__
First EditText is the share and the second value is its value calculated based on total and share. So, in example if I change any 1 share, all the values will be changed. So, shown in example total no of shares are = 1+1+1+2 = 5. So amount per share = 1000/5 = 200 and is calculated and shown in next EditText.
I have bound this values with two-way data binding like this:
As, this is a double value, I have added 2 binding adapters for this like this:
#BindingAdapter("android:text")
public static void setShareValue(EditText editText, double share) {
if (share != 0) {
editText.setText(String.valueOf(share));
} else {
editText.setText("");
}
}
#InverseBindingAdapter(attribute = "android:text")
public static double getShareValue(EditText editText) {
String value = editText.getText().toString();
if (!value.isEmpty()) {
return Double.valueOf(value);
} else
return 0;
}
Now, to calculate new values, I need to re-calculate whole thing after any share value is changed. So, I added android:onTextChagned method to update Calculations. But it gets me an infinite loop.
<EditText
android:text="#={items[id].share}"
android:onTextChanged="handler.needToUpdateCalculations"
.... />
public void needToUpdateCalculations(CharSequence charSequence, int i, int i1, int i2) {
updateCalculations();
}
This gets an infinete loop because when data changes, it is rebound to the EditText, and each EditText has an onTextChanged attached it will fire again and it will get really large - infinite loop.
It also updates the value of itself, ended up loosing the cursor as well.
I have also tried several other methods like adding TextWatcher when on focus and removing when losses focus. But at least it will update it self and will loose the cursor or infinite loop.
Unable to figure this problem out. Thank you for looking into this problem.
EDIT:
I have tried with the below method. But, it doesn't allow me to enter . (period).
#BindingAdapter("android:text")
public static void setDoubleValue(EditText editText, double value) {
DecimalFormat decimalFormat = new DecimalFormat("0.##");
String newValue = decimalFormat.format(value);
String currentText = editText.getText().toString();
if (!currentText.equals(newValue)) {
editText.setText("");
editText.append(newValue);
}
}
The reason you stated is correct and it will make a infinite loop definitely. And there is a way to get out from the infinite loop of this problem, android official provided a way to do so (But it is not quite obvious.)(https://developer.android.com/topic/libraries/data-binding/index.html#custom_setters)
Binding adapter methods may optionally take the old values in their
handlers. A method taking old and new values should have all old
values for the attributes come first, followed by the new values:
#BindingAdapter("android:paddingLeft")
public static void setPaddingLeft(View view, int oldPadding, int newPadding) {
if (oldPadding != newPadding) {
view.setPadding(newPadding,
view.getPaddingTop(),
view.getPaddingRight(),
view.getPaddingBottom());
}
}
You can use the old value and new value comparison to make the setText function called conditionally.
#BindingAdapter("android:text")
public static void setShareValue(EditText editText, double oldShare,double newShare) {
if(oldShare != newShare)
{
if (newShare!= 0) {
editText.setText(String.valueOf(newShare));
} else {
editText.setText("");
}
}
}

how to make a string case insensitive

I have one edittext and listview having some values. While typing text in edittext the listview contents will change according to the values typed inside edittext.
Now the problem is, the string is in case sensitive. ie, If the original text is Apparel, then if we type apparel or appa the original text is not displaying.
I want to make the string search case insensitive.
My code is,
private List<SearchList> searchTerms(List<SearchList> search_list, String s) {
List<SearchList> matches = new ArrayList<SearchList>();
for (SearchList search_lists : search_list) {
if (search_lists.search_term.contains(s)) {
matches.add(search_lists);
}
}
return matches;
}
Is there any way to achieve this. I have tried a lot.
string contains(); function is case sensitive.
And from your question, I've noticed that your list contains items with Capital letters as well in it.
So apply toLowerCase() to both side would cut it.
if (search_lists.search_term.toLowerCase().contains(s.toLowerCase()))
{
matches.add(search_lists);
}
Hope this helps.
Try to lower() a string:
private List<SearchList> searchTerms(List<SearchList> search_list, String s) {
List<SearchList> matches = new ArrayList<SearchList>();
for (SearchList search_lists : search_list) {
if (search_lists.search_term.contains(s.toLowerCase())) {
matches.add(search_lists);
}
}
return matches;
}
Just do as like and compare, Hope it will work :)
EditText editText= (EditText) findViewById(R.id.editText);
String editTextString=editText.getText().toString();
editTextString.equalsIgnoreCase(yourCompare);

android working with Views

In my activity I have the following views
TextView player1;
TextView player2;
TextView player3;
TextView player4;
EditText player1name;
EditText player2name;
EditText player3name;
EditText player4name;
Each of the TextView's has the onclick listener applied to it. and so fires the OnClick function.
When we get to the onClick this is what i am currently doing:
#Override
public void onClick(View v) {
//the v variable is the clicked textview, in this case "player1"
//hide the textview and show the resultant edittext
v.setVisibility(View.GONE);
player1name.setVisibility(View.VISIBLE);
//set focus on edit text and when focus is lost hide it and set the textview text
player1name.requestFocus();
imm.showSoftInput(player1name, InputMethodManager.SHOW_FORCED);
player1name.setOnFocusChangeListener(new OnFocusChangeListener() {
#Override
public void onFocusChange(View y, boolean x) {
v.setVisibility(View.VISIBLE);
player1name.setVisibility(View.GONE);
imm.hideSoftInputFromWindow(player1name.getWindowToken(), 0);
String name = player1name.getText().toString();
if (name.equals("")) {
v.setText("Player Name1");
} else {
v.setText(name);
}
}
});
}
However with this solution I will need to duplicate this code and change the view names for player2 - player2name, player3 - player3name etc
i can obviously grab the clicked TextView via v, however what i cant seem to do is grab its corresponding EditText.
i had thought of doing this:
View test = v + "name";
//then i replace all references to player1name with the test variable
but it doesnt work it wants me to convert View test; into a string
any suggestions?
EDIT: made it easier to understand my question
View test = v + "name";
will give a compile error. Because "v" is not a string type. and also even if it was String, test is not. This line is pretty wrong.
There a few options to achieve what you want,
You can use hashmap
Declare a global field for hashmap
private final HashMap<Integer,EditText> map = new HashMap<Integer,EditText>();
and in onCreate method put your textview id as key, and put your edittext variables in value.
player1name = (EditText) findViewById(R.id.player1name);
map.put(R.id.textView1, player1name);
// for the rest
in onClick method
EditText e = map.get(v.getId());
Then replace them with "e"
e.requestFocus(); //example
Will you please state your problem clearly? Currently, your language is very ambiguous and I can not figure out, exactly what are you looking for. It will help us to know your problem and in turn solve it.

How to allow only a valid floating point number into a text field in android

How to allow only a valid floating point number into a text field floating point like these only
2.353
-2.354
4444.45
Implement a focus listener on the field. When the focus changes from the textfield to any other part of your form simply use a regexp to check the validity of the input.
Something like :
^(-)?\d*(\.\d*)?$
Should do the trick.
Then use the pattern matching of Android to see if the input matches the regexp :
Pattern p = Pattern.compile("^(-)?\d*(\.\d*)?$");
Matcher m = p.matcher(inputString);
if (m.find()) {
////Found
}
else {
//Not found
}
But be aware of local settings...In France for example, the dot(.) used to separate the decimals is in fact a comma(,)
Use OnFocusChangeListener to achieve this.
//value pool
final String[] check = new String[]{"2.353","-2.354","4444.45"};
yourEditText.setOnFocusChangeListener(new OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
String s = ((EditText)v).getText().toString().trim();
for(String tmp : check){
if(!TextUtils.isEmpty(s) && s.equals(tmp)){
//it ok
break;
}
else{
//do something
}
}
}
});
For edittext use android:inputType="number"
Convert the resulting string into an integer (e.g., Integer.parseInt(myEditText.getText().toString())`).
android:inputType="numberDecimal|numberSigned"

TextView text formatted based on text value

I have an application where I need to display a list of numbers, but the numbers need to be formatted based on their value. Negative numbers are shown in normal text, positive numbers shown as bold. Also, the number needs to always appear positive in the text view. I tried extending TextView with setText overriden as such:
#Override
public void setText(CharSequence text, TextView.BufferType type) {
double number = Double.parseDouble(text.toString());
if (number > 0) {
this.setTypeface(this.getTypeface(), BOLD);
} else {
this.setTypeface(this.getTypeface(), NORMAL);
number = Math.abs(number);
}
super.setText(number + "", type);
}
This didn't quite work, as the setText was being called multiple times on the same MyTextView. This resulted in every number appearing bold, as it was positive the next time through.
I would like to keep this logic in a widget, as opposed to where the text is being set, as this is a very common occurrence in my application.
Is there a way that I can do this in a widget?
Just add a member variable to your class to check whether it was already modified or to keep the original value.
private double originalValue = 0;
#Override
public void setText(CharSequence text, TextView.BufferType type) {
if(originalValue==0) {
originalValue = Double.parseDouble(text.toString());
}
this.setTypeface(this.getTypeface(), originalValue>0 ? BOLD : NORMAL);
super.setText(Math.abs(originalValue), type);
}
Ok, I ended up just making an adapter for each list that used this special case, and took care of it in the activity for any other instance of it. Something like this:
#Override
public void bindView(View view, Context context, Cursor cursor) {
TextView text = (TextView) view.findViewById(R.id.special_text);
double amount = cursor.getDouble(cursor.getColumnIndex(DbAdapter.KEY_NUMBER));
if (amount > 0) {
amountText.setTypeface(null, Typeface.BOLD);
} else {
amountText.setTypeface(null, Typeface.NORMAL);
amount = Math.abs(amount);
}
text.setText(amount);
}

Categories

Resources