Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to prevent closing Navigation drawer by touch outside the drawer

I have an Activity with Navigation Drawer. if user device is table and orientation is landscape - I not need to close drawer by click on item in drawer:

if (!isTablet || context.getResources().getConfiguration().orientation==1) {
    mDrawerLayout.closeDrawer(Gravity.START);
}

It work. But if user touch the screen outside opened drawer - drawer closing. Using DrawerLayout.LOCK_MODE_LOCKED_OPEN is unsuitable bacause I need to save drawer sliding functions. How to prevent closing Navigation drawer when user touch outside the drawer?

Please, help.

like image 407
Anton Stukov Avatar asked Feb 20 '15 10:02

Anton Stukov


People also ask

What is drawer navigation?

The navigation drawer is a UI panel that shows your app's main navigation menu. The drawer appears when the user touches the drawer icon in the app bar or when the user swipes a finger from the left edge of the screen.

How to close navigation drawer in flutter?

When a user opens the drawer, Flutter adds the drawer to the navigation stack. Therefore, to close the drawer, call Navigator. pop(context) .


2 Answers

Based on the other answer which I wrote here. I have modified the code to suit your question. Please check.

Check more about touch hierarchy here

dispatchTouchEvent() method should be overridden in Activity class

@Override    
public boolean dispatchTouchEvent(MotionEvent event) {
    if (event.getAction() == MotionEvent.ACTION_UP) {
        if (isDrawerOpen()) { //Your code here to check whether drawer is open or not. 

            View content = findViewById(R.id.drawer); //drawer view id
            int[] contentLocation = new int[2];
            content.getLocationOnScreen(contentLocation);
            Rect rect = new Rect(contentLocation[0],
                contentLocation[1],
                contentLocation[0] + content.getWidth(),
                contentLocation[1] + content.getHeight());

            if (!(rect.contains((int) event.getX(), (int) event.getY()))) {
                isOutSideClicked = true;
            } else {
                isOutSideClicked = false;
            }

        } else {
            return super.dispatchTouchEvent(event);
        }
    } else if (event.getAction() == MotionEvent.ACTION_DOWN && isOutSideClicked) {
        isOutSideClicked = false;
        return super.dispatchTouchEvent(event);
    } else if (event.getAction() == MotionEvent.ACTION_MOVE && isOutSideClicked) {
        return super.dispatchTouchEvent(event);
    }

    if (isOutSideClicked) {
        return true; //restrict the touch event here
    }else{
        return super.dispatchTouchEvent(event);
    }
}

Note: As mentioned in the question comments, this is against of Android guidelines. So try to avoid it until unless it is mandatory.

like image 54
Noundla Sandeep Avatar answered Oct 27 '22 00:10

Noundla Sandeep


Simplified version of Noundla's answer which works for me. I wrote my custom Drawer which extends DrawerLayout and implement dispatchTouchEvent() method.

@Override
public boolean dispatchTouchEvent(MotionEvent event) {
    if (!this.isDrawerOpen(Gravity.LEFT)) {
        return super.dispatchTouchEvent(event);
    }
    boolean isOutSideClicked = false;
    if (event.getAction() == MotionEvent.ACTION_UP) {
        View content = findViewById(R.id.drawer_view); 
        int[] contentLocation = new int[2];
        content.getLocationOnScreen(contentLocation);
        Rect rect = new Rect(contentLocation[0],
                contentLocation[1],
                contentLocation[0] + content.getWidth(),
                contentLocation[1] + content.getHeight());
        isOutSideClicked = !(rect.contains((int) event.getX(), (int) event.getY()));
    }
    this.setDrawerLockMode(isOutSideClicked ? DrawerLayout.LOCK_MODE_LOCKED_OPEN : DrawerLayout.LOCK_MODE_UNLOCKED);
    return super.dispatchTouchEvent(event);
}

Also if you want to keep interact with main content fragment while drawer is open you should add this line at the beginning of the method.

getChildAt(0).dispatchTouchEvent(event);
like image 28
Anton Donov Avatar answered Oct 27 '22 01:10

Anton Donov