In my app, I have a RecyclerView with editable EditText views as part of the ViewHolder, see picture:
The user can edit the values of the EditText views. To save the changed value back to the related adapter, set an OnFocusChangeListener to the EditText views, storing the (changed) value as soon as they loose focus, see following code snippet, taken from the onBindViewHolder method of my adapter:
// Add listener to views
holder.fpuView.setOnFocusChangeListener((v, hasFocus) -> {
if (!hasFocus) {
// Focus has gone, so save value to adapter
mAbsorptionBlocks.get(position).setMaxFPU(Integer.valueOf(holder.fpuView.getText().toString()));
}
});
holder.absorptionTimeView.setOnFocusChangeListener((v, hasFocus) -> {
if (!hasFocus) {
// Focus has gone, so save value to adapter
mAbsorptionBlocks.get(position).setAbsorptionTime(Integer.valueOf(holder.absorptionTimeView.getText().toString()));
}
});
This works fine, as long as the user taps another EditText view.
It does NOT work if the user directly hits the "Save" button immediately after having changed the value of the EditText. The EditText seems not recognize that is has lost focus. This is probably due to the Save button does not belong to the RecyclerView, but to the parent activity.
I played around with other listener options, but I'm pretty lost now. Is there any chance to grasp the changed values when the user hits the Save button directly after editing the value?
You must these method of EditText
holder.fpuView.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) {
if(s.length() != 0) {
mAbsorptionBlocks.get(position). setMaxFPU(Integer.valueOf(holder.fpuView.getText().toString()));
}else{
// add default value when EditText is empty.
}
}
});
Use OnTestChangeListener instead. Then catch the after text changed event or in real time if you prefer. That way you aren't relying on the focus change event to get the text.
Related
I have an Activity with a fragment... In this fragment I'm using two-way DataBinging in an EditText. This EditText is binded to a Double property of the object, and because of this, I had to implement an InverseMethod to convert String -> Double and Double -> String...
In my EditText I configured android:selectAllOnFocus="true", and I'm forcing it also on onCreateView method of the fragment: edQtd.selectAll()
The problem is, that when the fragment appears, the EditText has the focus, but the text is not selected, instead, the cursor is before the first number...
I wanted it to show with all the text selected...
Tried to instead of using the inverse method, just concatenate an empty String, but the result was the same...
From what I saw debbuging it, the binding class generated, sets the text after the fragments creation (after I manually called edQtd.selectAll()), removing the selection...
Any ideas how to solve it?
Edit:
For now I solved it adding a TextChangedListener to the EditText, where I select all the text only the first time the text is changed:
edQuantidade.addTextChangedListener(new TextWatcher() {
#Override
public void afterTextChanged(Editable s) {
if(selectAllEdQtdText) {
edQuantidade.selectAll();
setSelectAllEdQtdText(false);
}
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
});
Add following attributes on EditText in Layout.
<EditText
android:focusable="true"
android:focusableInTouchMode="true"
android:selectAllOnFocus="true"
/>
And remove edQtd.selectAll() from code.
Edit
Because none solution works. This will work because this will trigger selectAll after a delay. Add this after setting model in binding.
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
#Override
public void run() {
edQtd.selectAll();
}
}, 500);
This question already has an answer here:
automatically update my activity to show which was written
(1 answer)
Closed 8 years ago.
Using a text field, how would I set the text of a TextView while constantly updating the text? For example: The user begins to type information into the text field, this changes some text in in the activity they're in, however, the user does not need to manually update the text, instead the text automatically refreshes.
I have tried doing this myself and searched for other dilemmas, yet nothing appears to work. Additionally, I'm working with fragments that could possibly cause the problem. The code is below, partitioned into areas, before onCreateView(), in onCreateView() and after onCreateView().
Before onCreateView():
// Edit Text
EditText exerciseOneTitle;
// String value, contains value of exerciseOneTitle
String value;
// titleOne, what I want to the user to be able to change
TextView titleOne;
During onCreateView():
// Edit text
exerciseOneTitle = (EditText) rootView.findViewById(R.id.exercise_text);
// Get Edit Text value
value = exerciseOneTitle.getText().toString();
// Set title so there is always an initial value
titleOne.setText(R.string.exercise_one);
// Checks if edit text is focused
exerciseOneTitle.setOnFocusChangeListener(new OnFocusChangeListener() {
public void onFocusChange(View v, boolean hasFocus) {
// While edit text is focused, update titleOne via refresh()
while (hasFocus == true) {
refresh();
}
}
});
After onCreateView():
// Get the updated "value" and set it as titleOne text
// Additionaly, will be using it in other situations
public void refresh() {
value = exerciseOneTitle.getText().toString();
titleOne.setText(value);
}
Any thoughts or ideas? Thanks!
You can use TextWatcher.. See the link
According to the docs
onTextChanged() is called to notify you that, within s, the count
characters beginning at start have just replaced old text that had
length before. It is an error to attempt to make changes to s from
this callback.
Try this..
tv = (TextView)findViewById(R.id.charCounts);
textMessage = (EditText)findViewById(R.id.textMessage);
textMessage.addTextChangedListener(new TextWatcher(){
public void afterTextChanged(Editable s) {
tv.setText(textMessage.getText().toString());
}
public void beforeTextChanged(CharSequence s, int start, int count, int after){}
public void onTextChanged(CharSequence s, int start, int before, int count){}
});
In my tablet app I have used fragments and one fragment has multiple Edittexts, and I have a linear layout which will add a sublayout as many times the user wishes to add, in that fragment
This sublayout has two edittext, both this edittext is having
addtextchangelistener(Textwatcher) and
onfocuschangelistner
every time the text is changed 3 conditions are checked in both the edittext
every time the focus is changed 2 conditions are checked in both the edittext
After doing all this condition check, the problem I'm facing is, the edittext typing is too slow, its like i type an email and the whole email gets completely typed after 5 secs or more,
This is the code for 1 edit text in the sublayout:
receiverName.setOnFocusChangeListener(new OnFocusChangeListener() {
#Override
public void onFocusChange(View paramView, boolean hasFocus) {
receivernameFocus = hasFocus;
if(hasFocus)
{
if(receiverName.getText().toString().length()>0)
ReceiverName_btn_cancel.setVisibility(View.VISIBLE);
else
ReceiverName_btn_cancel.setVisibility(View.INVISIBLE);
}
else
ReceiverName_btn_cancel.setVisibility(View.INVISIBLE);
}
});
receiverName.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence paramCharSequence, int paramInt1,int paramInt2, int paramInt3) {
if(receivernameFocus)
{
if(receiverName.getText().toString().length()>0)
{
receiverNamePresent = true;
ReceiverName_btn_cancel.setVisibility(View.VISIBLE);
}
else
{
receiverNamePresent = false;
ReceiverName_btn_cancel.setVisibility(View.INVISIBLE);
}
}
else
ReceiverName_btn_cancel.setVisibility(View.INVISIBLE);
if(receiverEmailPresent && receiverNamePresent)
addReceiver.setBackgroundResource(R.drawable.plus_receiver);
else
addReceiver.setBackgroundResource(R.drawable.plus_deselect_receiver);
}
#Override
public void beforeTextChanged(CharSequence paramCharSequence,
int paramInt1, int paramInt2, int paramInt3) {
}
#Override
public void afterTextChanged(Editable paramEditable) {
}
});
same conditions are present for the other edittext, and everytime the user inflate another view, same set of edittext will be created for the new view too.
I can't remove the conditions, all of them are necessary, and you can see its just some button visibility or setting background resource
How to optimize this code, or how to speed up the edittext typing speed for android tablet?
EDIT: If I'm typing 10 letters persecond its showing only 1 letter per second in the edittext(so all the 10 letters will be visible in the edittext after 10 seconds), which I believe is happening because of multiple condition checking within onTextChanged method, the delay in showing the text is too much for user experience.
How to make the edittext show the text as fast as I'm typing it
Thanks
Here public void onTextChanged(CharSequence paramCharSequence, int paramInt1,int paramInt2, int paramInt3) it's generally in this format:
public void onTextChanged(CharSequence s, int start, int before, int count)
So here you will need to do some operation using paramInt3 . If you would like to show suggest text will come after you enter 3 letter then perform an operation here in this manner:
public void onTextChanged(CharSequence s, int start, int before, int count)
{
if (count%3 == 1)
{
adapter.clear();
GetPlaces task = new GetPlaces();
task.execute(dep_place.getText().toString());
}
}
here I haved updated text from server side in background. You just need to modify this portion from where your text will come use this code here.
Thanks.
I have this application in which I create multiple EditTexts dynamically. The amount depends on user input. I am trying to allow the focus to change to the next edittext after two characters have been entered. I have this so far:
for(EditText editText : editTextList ) {
editText.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// TODO Auto-generated method stub
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// TODO Auto-generated method stub
}
#Override
public void afterTextChanged(Editable s) {
if(s.toString().length() == 2) {
//code to change focus to next edit text goes here
}
}
});
}
The first problem is that this could potentially create many instances of TextWatcher if the user enters a large number (average in this context would probably be 100-600 EditText fields).
The second problem is how would I go about changing focus in the afterTextChanged method because I would want to change the focus to the next EditText away from the one that is currently being represented inside the loop.
Should I not be concerned about the potential performance issues of multiple TextWatcher objects? Should I scrap this whole implementation and focus elsewhere? Any suggestions will be greatly appreciated.
As you may have a lot of EditTexts at runtime i would suggest you to use maxlength attribute of EditText in this way you will restrict user to enter only 2 characters.
like this
EditText editText = new EditText(this);
int maxLength = 2;
editText.setFilters(new InputFilter[] {new InputFilter.LengthFilter(maxLength)});
Now add next button in your keyboard like this
yourEditText.setImeOptions(EditorInfo.IME_ACTION_NEXT);
It is the default behavior of next button to change focus to the immediate next view which takes input being in the same parent layout.
My app should open a file inside an edittext to show it to the user. If user want to modify it just press inside textwiew and write it. After do this when back button is pushed, if the text was modify, the changes should be saved, else, just close the current activity and go to parent.
There's a way to see if the text was edited?
My idea is to explicitly compare file and edittext character length, but there's something better than this "rude" method?
You can use a TextWatcher:
boolean changed = false;
EditText edit = (EditText)findViewById(R.id.medittext);
edit.addTextChangedListener(new TextWatcher() {
#Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// TODO Auto-generated method stub
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
changed = true;
}
});
Just comparing the length might result in a false negative if the changes are of the same length as deletions in the text.
When the user presses back, just check if changed is true. This might result in a false positive if the user made an edit and then undid it, but it is better to have a few false positives than to lose user changes.
Nothing better actually you have to compare the text and not the length. The user could just replace a word. A TextWatcher would tell you that a user is editing but he just may change and change it back. So you really need to compare strings.