简体   繁体   中英

Force EditText to lose focus when back pressed

I'm trying to force the EditText control to lose focus when the user presses the back button to hide the keyboard. There are many questions similar to this already, but after several hours, I haven't been able to make it work.

First, just a little bit of context. I have a ListView with custom items. Each item has several TextViews and one EditText. I have an AfterTextChanged() method saving edited values. I have a style set up to highlight the field if it has focus. Unfortunately, it is now much more obvious that the EditText doesn't actually lose focus when you hide the (soft) keyboard, and I think it's confusing. I would like the EditText to not be focused if there's no keyboard.

The solution that seemed the most reasonable is to override OnBackPressed() in the activity as described here . Unfortunately, it doesn't appear that my method is being called. Ie the field is still focused, and a breakpoint in the function doesn't fire.

Similarly, an OnKeyUp() listener on the activity doesn't fire, and Xamarin doesn't appear to support the OnKeyUp handler for the EditText control.

I'm not trying to suppress the keyboard on creation, or anything, so using any of the invisible control tricks don't help either.

It's obvious that a lot of people have this problem. I'm sure one of you has solved it! Can you please share your solution?

Thank you so much! -Karen

PS I do not need to know how to hide the keyboard. I need to take an action when the user hides the keyboard with the back button. Thanks :)

In my experience onBackPressed() (at least the default @Override one in an activity) will not normally fire when pushing the back button to close the keyboard. As far as I know it will only fire when a Back press would initiate a finish() on the current activity.

Below is a kind of "hacky" way to know when the keyboard is shown/hidden by monitoring the change in the view size. You must also set the Activity to android:windowSoftInputMode="adjustResize" in the AndroidManifest.xml.

final View activityRootView = findViewById("Your main View");
    activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        Rect r = new Rect();
        //r will be populated with the coordinates of your view that area still visible.
        activityRootView.getWindowVisibleDisplayFrame(r);

        int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
        if (heightDiff > 100) { // if more than 100 pixels, its probably a keyboard...
          //Keyboard is shown


        }
        if(heightDiff <= 100) {
            //Keybaord not shown
        }
     }
    });

With sincere thanks to @Shadesblade (and Xamarin's sample code), my EditTexts now unfocus! Here's the Xamarin-ized solution:

To your activity, add this class:

class GlobalLayoutListener : Java.Lang.Object, ViewTreeObserver.IOnGlobalLayoutListener
{
    Action on_global_layout;
    public GlobalLayoutListener (Action onGlobalLayout)
    {
        on_global_layout = onGlobalLayout;
    }

    public void OnGlobalLayout ()
    {
        on_global_layout ();
    }
}

Add a class variable to hold the View so that the delegate can access it:

View _rootview;

In your OnCreate() add:

GlobalLayoutListener gll = new GlobalLayoutListener(
    delegate {
        Android.Graphics.Rect r = new Android.Graphics.Rect();
        _rootView.GetWindowVisibleDisplayFrame(r);
        int heightDiff = _rootView.RootView.Height - (r.Bottom - r.Top);
        if (heightDiff < 100)
        {
            if (Window.CurrentFocus != null)
                Window.CurrentFocus.ClearFocus();
        }
    });

_rootView = FindViewById<View>(Resource.Id.relativeLayoutOrder);
_rootView.ViewTreeObserver.AddOnGlobalLayoutListener(gll);

I expect to need to dork around with the heightDiff level and/or have to add some rotation checking, but I haven't done any rotation support at this point, so I can punt that until later.

Thank you again! * happy dance *

adding on to Shadesblade's answer, if you are using a scrollview, his answer needs a change to work, because not all of the scrollview is showing on screen. so instead of doing

int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);

you should do

int heightDiff = Utils.getScreenHeight(SearchActivity.this) - (r.bottom - r.top);

where Utils.getScreenHeight is this:

public static int getScreenHeight(Context c) {
    if (screenHeight == 0) {
        WindowManager wm = (WindowManager) c.getSystemService(Context.WINDOW_SERVICE);
        Display display = wm.getDefaultDisplay();
        Point size = new Point();
        display.getSize(size);
        screenHeight = size.y;
        screenWidth = size.x;
    }
    return screenHeight;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM