OnFocusChange not always working - android

In one of my activities I have three EditTexts and an OK button. The OnFocusChangeListener is set to all three EditTexts. The listener should trigger every time the focus is lost.
Switching between EditTexts works perfectly. But if the user presses the OK button there's no focus change (losing the focus) triggered for the EditText the user focused before pressing the button.
What's wrong with my code?
private class MyOnFocusChangeListener implements OnFocusChangeListener {
private EditText editText;
public MyOnFocusChangeListener(final EditText editText) {
super();
this.editText = editText;
}
#Override
public void onFocusChange(final View view, final boolean isFocused) {
if (!isFocused) {
if (editText == editText1) {
// Do a calculation
} else if (editText == editText2) {
// Do another calculation
} else if (editText == editText3) {
// Do a different calculation
}
}
}
}
#Override
public void onCreate(final Bundle bundle) {
// ...
editText1.setOnFocusChangeListener(new MyOnFocusChangeListener(editText1));
editText2.setOnFocusChangeListener(new MyOnFocusChangeListener(editText2));
editText3.setOnFocusChangeListener(new MyOnFocusChangeListener(editText3));
// ...
}

You could try to clear the focus when user click on OK or other button....
e.g.
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int whichButton)
{
editText1.clearfocus();
editText2.clearfocus();
editText3.clearfocus();
....
}
}

You might want to try using: addTextChangedListener(..) in this case.

Sounds like you could be having issues with touch mode, from the android docs:
"The relationship between touch mode, selection, and focus means you must not rely on selection and/or focus to exist in your application."

To expand on #dong221, and incorporating the comment made by #Harald, one way to clear the focus without having to keep track of the last selected EditText is to get a reference to the currentFocus from the window object. Something like this:
myDoneButton.setOnClickListener { v ->
// Assuming we are in an Activity, otherwise get a reference to the Activity first
window.currentFocus?.clearFocus()
}

It works if you bind onFocusChangeListener to the view element you want to be observed
editText.onFocusChangeListener = this
editText.setOnClickListener(this)
by keyword this it means the ViewHolder class

Related

Android - Calling a DialogFragment method from a Class to close the soft keyboard of DialogFragment

Good day. Sorry for the long title, I had to be descriptive.
I have an Android Application where I have a Custom ListView with an EditText and a DialogFragment on top of it. The user can still see the EditText as the DialogFragment does not cover the whole screen and the user can still select the EditText in the ListView. The EditText in my Custom ListView has a custom Keyboard from this tutorial. My Dialog Fragment contains an Edit Text that uses the default Android Soft Keyboard.
The main issue/problem I have is that when the user clicks the EditText in my Dialog Fragment (the android soft keyboard shows up) and clicks on the EditText in the Custom ListView, my Custom Keyboard shows up behind the Android Soft Keyboard and the Android Soft Keyboard does not collapse/hide.
One work around I did was this:
I made the root view of the Dialog Fragment (the parent view of the EditText) be selectable as such:
android:clickable="true"
android:focusableInTouchMode="true"
So that the focus isn't "locked" or monopolized by the EditText. I also created a function in the DialogFragment class that hides the soft keyboard. I have two of them and they both work:
public void hideKB(){
InputMethodManager imm = (InputMethodManager)getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(instructionInput.getWindowToken(), 0);
//instructionInput is my EditText
}
public void hideKeyboard(View view) {
InputMethodManager imm =(InputMethodManager)getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
And I call either of them as such:
instructionInput.setOnFocusChangeListener(new View.OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) {
hideKB();
//hideKeyboard(v);
}
}
});
And it works fine. When the user clicks on the Dialog Fragment the soft keyboard closes.
Now, I want to call this function or achieve the same effect when the user clicks on the EditText in my Custom ListView. The Custom Keyboard class in my EditText has this function:
public void registerEditText(int resid, final SearchResult context, final ItemDialog itemDialog) {
EditText edittext= (EditText)mHostActivity.findViewById(resid);
edittext.setOnFocusChangeListener(new OnFocusChangeListener() {
#Override public void onFocusChange(View v, boolean hasFocus) {
if( hasFocus ) {
Log.d("hello","edittext focused");
itemDialog.hideKB();
showCustomKeyboard(v);
}
else {
hideCustomKeyboard();
}
}
});
//removed extra lines of code
}
Kindly not that SearchResult is the Base Activity of the DialogFragment and that ItemDialog is my Dialog Fragment.
What I do is that when the user focuses on the EditText in the ListView, the onFocusChange function triggers and I try to call the hideKB() function of my Dialog Fragment. However, I am thrown a nullPointerException:
FATAL EXCEPTION: main
Process: com.agict.marswin, PID: 14038
java.lang.NullPointerException
at UtilityClasses.CustomKeyboard$2.onFocusChange(CustomKeyboard.java:187)
and Line 187 at my CustomKeyboard is the code that calls the function from the Dialog Fragment:
itemDialog.hideKB();
And I don't get why I am getting a null pointer at that line because I called the registerEditText after I initialized my itemDialog. I think my issue boils down to calling a function of a DialogFragment from a class.
Can anyone help me? I've been working on this for the past 6+ hours and I'm stuck. Any help is very much appreciated. Thanks.
Okay sorry, I got it to work. The problem was the itemDialog was null. What I did instead was this:
In my SearchResult activity, I created a public ItemDialog as such:
public ItemDialog itemDialog;
Then I instantiated it normally, created, and showed it. So now I have a properly instantiated DialogFragment that can be accessed by any class since it's public.
Going to the registerEditText() function, here's what I did:
public void registerEditText(int resid, final SearchResult searchResult, final ItemDialog itemDialog) {
#Override
public void onFocusChange(View v, boolean hasFocus) {
if( hasFocus ) {
Log.d("hello","edittext focused");
searchResult.itemDialog.hideKB();
showCustomKeyboard(v);
}
else {
hideCustomKeyboard();
}
}
//extra code here
}
Since I am passing the activity to the registerEditText function as such in my SearchResult Activity:
mCustomKeyboard.registerEditText(R.id.qtyInputSearchResult, SearchResult.this, itemDialog);
mCustomKeyboard.registerEditText(R.id.discInputSearchResult, SearchResult.this, itemDialog);
(actually the last argument is no longer needed)
I can use the 2nd argument SearchResult to access the itemDialog variable (which is not null and perfectly instantiated) and from there, I can properly call my function.
I know this isn't the best way to go about it, but so far, it works.

using onClick on TextView with selectable text - how to avoid double click?

This is so strange, but if you put an onClickListener on a TextView (or non-editable EditText) which has android:textIsSelectable="true" - it needs not one tap, but two.
I checked it on 3 phones and all of them perform onClick only after second tap.
Of course, if you make focusable="false" or android:textIsSelectable="false" it works from the 1st tap, but text selection doesn't work.
Please, help me with that issue
Set in XML to your TextView:
android:textIsSelectable="true"
After that set onTouchListener to your TextView and in them do this:
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) view.requestFocus();
It's set focus for every tap on TextView.
After all set onClickListener to your TextView.
I have the same problem with a ViewHolder in my RecyclerView.Adapter. So, I cut it for you if you need:
class RollHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnTouchListener {
private TextView textView;
RollHolder(View itemView) {
super(itemView);
textView = (TextView) itemView.findViewById(R.id.text_view);
textView.setOnClickListener(this);
textView.setOnTouchListener(this);
}
#Override
public void onClick(View view) {
switch (view.getId()){
case R.id.text_view:
// Do here that you need
break;
}
}
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
switch (view.getId()){
case R.id.text_view:
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) view.requestFocus();
break;
};
return false;
}
}
I had the same problem and it's hard to ask and search for a resolution.
Here are two things that I noticed in addition to the double tap behavior:
if you really double tap (quickly) on a TextView with textIsSelectable, it selects the word you tapped, even when the focus is on something else, which means the view somehow registered the first touch as well.
if you long tap while the focus is somewhere else, it works and starts the selection action mode as if it was focused already
Here's how I managed to make it work. It's not beautiful, but everything works fine so far: in the XML you only need to add textIsSelectable, no other focusable / focusableInTouchMode / clickable / enabled attributes needed; then you need two listeners, one is the existing onClick which works, but needs a double take and the other is an onFocusChange where you handle the exceptional first tap:
hint = (TextView)view.findViewById(R.id.hint);
hint.setOnClickListener(new OnClickListener() {
#Override public void onClick(View v) {
handleHintClick();
}
});
hint.setOnFocusChangeListener(new OnFocusChangeListener() {
#Override public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) { handleHintClick(); }
}
});
Here is an alternative solution in a related question which I don't like and didn't even try: wrap the TextView in a FrameLayout and add the listener to that.
Here is another related question which has more solutions.
Use onTouchListener to detect clicks and redirect them to the container view:
textView.setOnTouchListener { _, event ->
if (event.action == 1 && !textView.hasSelection()) {
containerView.callOnClick()
}
false
}
This will keep the ability to select and unselect text without calling onClick event.
android:longClickable="false"
android:clickable="false"
Disable the button with setEnabled(false) until it is safe for the user to click it again.
May this helpful to you
Try this.
use in XML file
android:onclick"your Name"//for example I used "onImageListClick"
public void onImageListClick(View view)
{
//do your task.
//Intent intent = new Intent(this, ImageListActivity.class);
//intent.putExtra(Extra.IMAGES, IMAGES);
//startActivity(intent);
}
or
txtboxname.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
////do you task.
}
});

Android - Do something *after* text is changed in EditText

I build an android application. I have an EditText. I want to save changes (or anything else) automatically after the user change the text.
Now I use
editText.addTextChangedListener(textWatcher);
and
TextWatcher textWatcher = new TextWatcher() {
public void afterTextChanged(Editable s) {
...
}
But it saves the changes after every little change (add \ remove a letter), and I want that it'll be saved only after the user finished (closed the keyboard, clicked on a different edittext, etc. ).
How can I do that?
Implement onFocusChange of setOnFocusChangeListener and there's a boolean parameter for hasFocus. When this is false, you've lost focus to another control and you should save the data of editext. for example
EditText editText= (EditText) findViewById(R.id.editText);
editText.setOnFocusChangeListener(new OnFocusChangeListener() {
public void onFocusChange(View v, boolean hasFocus) {
if(!hasFocus) {
//SAVE THE DATA
}
}
});
Implement setOnFocusChangeListener for all EditTexts and you should handle Back Press event too. If the user change the data of edittext and didn't goto another EditText and pressed back then edited vallue will not save. So should use onKeyDown or onBackPressed too
As Kotlin is now official android language:
var editText = findViewById<EditText>(R.id.editText)
editText.onFocusChangeListener = OnFocusChangeListener { _, hasFocus ->
if (!hasFocus) {
//SAVE THE DATA
}
}

EditText focus in android

In my application when I click an EditText, I have to perform some logic. I have the code. But it is not going into the click method.
My code:
EditText des=(EditText)findViewById(R.id.desinc);
des.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
java.lang.System.out.println("Inside click");
EditText income=(EditText)findViewById(R.id.editText1);
// TODO Auto-generated method stub
String inc=income.getText().toString();
int indexOFdec = inc.indexOf(".");
java.lang.System.out.println("index="+indexOFdec);
if(indexOFdec==0)
{
java.lang.System.out.println("inside index");
income.setText(inc+".00");
}
}
});
What am I doing wrong? Help me.
Try overriding onTouch by setting up an onTouchListener in the same way as an onClickListener. Use this code as a reference.
EditText dateEdit = (EditText) findViewById(R.id.date);
date.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
//anything you want to do if user touches/ taps on the edittext box
}
return false;
}
});
UPDATE(why this behavior):
The first click event focuses the control, while the second click event actually fires the OnClickListener. If you disable touch-mode focus with the android:focusableInTouchMode View attribute, the OnClickListener should fire as expected.
You can also try this: set android:focusableInTouchMode="false" for your EditText box in the xml. See if it works with the existing code.
You should use OnFocusChangeListener()
Try clicking EditText twice because at first instance EditText gets focus and after that EditText's click event executes. So, if you want your code to execute on first click write your code for focus change of EditText using OnFocusChangeListener().

Single click edittext

How can make an EditText have a onClick event so that on single click an action is done.
private void addListenerOnButton() {
dateChanger = (EditText) findViewById(R.id.date_iWant);
dateChanger.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
showDialog(DATE_DIALOG_ID);
}
});
}
this is not working as excepted....single click gives just the onscreen keypad but not the datepicker dialog which appears only if i double click
if we just add android:focusableInTouchMode="false" in edittext on layout page it should work in a singleclick on its onclicklistener. no need to handle onFocusChangeListener.
Change your code from an onClickListener to an OnFocusChangeListener.
private void addListenerOnButton() {
dateChanger = (EditText) findViewById(R.id.date_iWant);
dateChanger.setOnFocusChangeListener(new OnFocusChangeListener() {
public void onFocusChange(View v, boolean hasFocus) {
if(hasFocus) {
showDialog(DATE_DIALOG_ID);
}
}
});
}
EditText is not meant for singleClick.
I mean you should not use Click Listener with it.
rather you can do like,
Use onFocusChangeListener which is also not 100% correct approach.
Best would be instead the EditText use one TextView write onClick of that and if needed give a background image to that TextView.
Rewrite
I have an EditText that launches a dialog when the user either clicks it once or navigates to it with a trackball / directional pad. I use this approach:
Use an OnFocusChangeListener for gaining focus to open the dialog.
Override dismissDialog() to clear the focus from the EditText when the user closes the dialog, preventing the user from entering text without the dialog (as far as I can tell)
.
I have also tried this (however I now remember this method did respond to trackball movement):
Use an OnClickListener for touch events.
Set setFocusable(false) to prevent user input.
Hope that helps.

Categories

Resources