Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to clear focus of all selectable elements in a View?

My problem is simple. How to Clear Focus of all the elements in a View that may have focus (like EditText -or- TextView whose textIsSelectable="true" and the text is selected in it at occurrence of the clearFocus event).

Why am asking (in case I don't get a generic reply to above) :

I have few fragments that am accessing through Navigation View. My main goal is to lose focus of the elements in the fragment on Drawer open in Navigation View. I know its possible to get onDrawerSlide method for the NavigationDrawer and have infact set it up in my MainActivity so that on drawer open, if my EditText in one of the Fragments is open, I call hideSoftKeyboard code so that it closes the SoftKeyboard.

My Code to get the event on Opening of Drawer: (in onCreate() method of MainActivity)

DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
                this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close)
{
            //Hide SoftKeyboard on Navigation Drawer Open
            @Override
            public void onDrawerSlide(View drawerView, float slideOffset) {
                //Hide SoftKeyboard if it is open
                hideSoftKeyboard();

                //And Make any view having focus loose focus
 //...
//ClearFocus for the whole view is done from here (for whichever Fragment is visible right now)

                super.onDrawerSlide(drawerView, slideOffset);
            }        
};

public void hideSoftKeyboard()    //Declared outside onCreate
{
        InputMethodManager inputMethodManager = (InputMethodManager)getSystemService(Activity.INPUT_METHOD_SERVICE);
        inputMethodManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
}

Here, my hideSoftKeyboard() code is generic and can close SoftKeyboard no matter what Fragment is visible at the moment from the MainActivity itself. Similarly I want to clearFocus of all my EditTexts and TextView (since Copy/Paste option shows up in middle of the drawer when it is open).

I know I can write code for each Fragment calling onDrawerSlide function and clearing Focus for each element individually, but I want to know if it is possible for a generic solution and if so, how to do it.

(If it is possible, there might be many implications of this and may help in a lot many cases)

like image 651
Kaushik NP Avatar asked Feb 26 '17 19:02

Kaushik NP


3 Answers

Well, I finally decided I couldn't wait any longer for a general answer and so decided to implement the onDrawerSlide for each fragment. Turns out, even that is a bit tricky since you need to access your toolbar and setup your drawer using current drawer and a little bit of experimenting was throwing up NPE! (Just my usual luck)

So was going through the official android developers site for any insight when this flashed to me. Why not use getCurrentFocus to get my present view and then clearFocus()! And voilla, it works. I was focusing on the complex situation so much that I forgot to check on the easy parts.

So here's the answer to my own question: (in onCreate for MainActivity)

DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close)
{
            @Override
            public void onDrawerSlide(View drawerView, float slideOffset) {
                hideSoftKeyboard();

                getCurrentFocus().clearFocus();  //clear focus - any view having focus

                super.onDrawerSlide(drawerView, slideOffset);
}

Thanks to @keivan Esbati for pointing out a loophole that I didn't notice due to my usage of dummy view (used in layout xml so that as soon as Layout is loaded, the first EditText does not get the focus). As per Android Developer forum :

clearFocus() : When a View clears focus the framework is trying to give focus to the first focusable View from the top. Hence, if this View is the first from the top that can take focus, then all callbacks related to clearing focus will be invoked after which the framework will give focus to this view.

A round-about to this is ofcourse to set up a dummy variable that calls focus as soon as Layout is loaded (method I used) or this as shared by @keivan.

like image 188
Kaushik NP Avatar answered Oct 13 '22 09:10

Kaushik NP


To Clear focus from a View you can call getCurrentFocus().clearFocus() But remember that this will Simply move focus from current view to the first element in your view, not Completely removing focus from views; So if the first element in your layout is a EditText it's going to gain focus again.

A way to make sure your view doesn't get focus again is to add this attributes to your root view in your xml, enabling root view to capture focus:

android:focusableInTouchMode="true"
android:descendantFocusability="beforeDescendants"

So if you declare your root element like below it gonna automatically catch focus before it reach the child views:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:focusableInTouchMode="true"
    android:descendantFocusability="beforeDescendants">

    <!-- Rest of Layout -->
    <.../>

</LinearLayout>
like image 28
Keivan Esbati Avatar answered Oct 13 '22 09:10

Keivan Esbati


If you have multiple activity and in those activities only one activity you have Navigation View. In that case if you want to clear focus on navView use this code,

@Override
protected void onResume() {
    super.onResume();

    int size = navigationView.getMenu().size();
    for (int i = 0; i < size; i++) {
        navigationView.getMenu().getItem(i).setChecked(false);
    }

}
like image 32
Nazmus Saadat Avatar answered Oct 13 '22 08:10

Nazmus Saadat