Set drag margin for Android Navigation Drawer
Asked Answered
N

2

34

I am using the new Navigation Drawer in my app. It is great except I have not found an easy way to set how the drawer is open. The default behavior is drag from the left edge of the screen to open. This is fine, unless the phone/table has a case on and the edge of phone can not be touched. I would like to allow the user to touch and drag from a margin of the screen to the left. This is easy to set with other nav drawer libs(Sliding lib). I have not seen anything with Google's lib unfortunately.

There is an onTouchEvent() method for the NavigationLayout that could may be used. Of course you could listen to all touch events and trigger an openDrawer, but was hoping for an easy way with less code. Any ideas?

Neela answered 7/6, 2013 at 16:12 Comment(1)
+1 I'm also interested in figuring this out.Ezaria
E
70

Here I've found a solution via reflections

DrawerLayout mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
Field mDragger = mDrawerLayout.getClass().getDeclaredField(
        "mLeftDragger");//mRightDragger for right obviously
mDragger.setAccessible(true);
ViewDragHelper draggerObj = (ViewDragHelper) mDragger
        .get(mDrawerLayout);

Field mEdgeSize = draggerObj.getClass().getDeclaredField(
        "mEdgeSize");
mEdgeSize.setAccessible(true);
int edge = mEdgeSize.getInt(draggerObj);

mEdgeSize.setInt(draggerObj, edge * 5); //optimal value as for me, you may set any constant in dp
Eck answered 23/7, 2013 at 6:6 Comment(6)
Hack don't really work especially when its content is ViewPager. When swiping toward left, with NavigationDrawer, ViewPager won't change from view 0 to view 1. All the events are consumed by NavigationDrawer.Biconvex
@CheokYanCheng That's obvious. You cannot have it both ways :)Filbert
@Maxim: I test with Android 5.0 and it is not working smoothly. When sliding near middle screen, the left screen could not move to right all!Zerlina
Default edge size is 20 dp, you can check the source code of ViewDragHelper.java, final ViewConfiguration vc = ViewConfiguration.get(context); final float density = context.getResources().getDisplayMetrics().density; mEdgeSize = (int) (EDGE_SIZE * density + 0.5f);Lethalethal
Is there any direct api to do this?Obtain
it worked with "androidx.drawerlayout:drawerlayout:1.0.0" but not with "androidx.drawerlayout:drawerlayout:1.1.1"Demisec
D
2

It's a really old question, but I hit that issue nowadays, I tried the original solution, but it didn't work for me.

After hours of trying, I found out that the issue is not with the solution. It's with the library version change.

The accepted answer worked for android.drawerlayout:drawerlayout:1.0.0

but for me, I was using com.google.android.material:material:1.5.0, which depends on a higher version of drawerlayout:drawerlayout

The android team have added some logic on onLayout to set the Edge Size.

So I used the original solution, but instead of using it in the activity, I created a Custom View Based on DrawerLayout.

So here is my custom class:

class CustomDrawerLayout : DrawerLayout {
    var swipeEdgeSize = 0

    constructor(context: Context) : this(context, null, 0)
    constructor(context: Context, attrs: AttributeSet) : this(context, attrs, 0)
    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
        context,
        attrs,
        defStyleAttr
    )

    override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
        super.onLayout(changed, l, t, r, b)
        var leftDraggerField = DrawerLayout::class.java.getDeclaredField("mLeftDragger")
        leftDraggerField.isAccessible = true
        val viewDragHelper = leftDraggerField[this] as ViewDragHelper

        val edgeSizeField = ViewDragHelper::class.java.getDeclaredField("mEdgeSize")
        edgeSizeField.isAccessible = true
        val origEdgeSize = edgeSizeField[viewDragHelper] as Int
        edgeSizeField.setInt(viewDragHelper, max(swipeEdgeSize, origEdgeSize))
    }
}

and inside the activity, I will use something like that

class MainActivity :....{
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(....)
        setSideMenuAreaRatio(0.8)
        ....
    }

private fun setSideMenuAreaRatio(ration: Double) {
        val displaySize = Point()
        windowManager.defaultDisplay.getSize(displaySize)
        binding.drawerLayout.swipeEdgeSize = (displaySize.x * ration).toInt()
    }
}

But if you are starting your new project, use the jetpack compose. It doesn't have this issue.


Also to make sure that that solution only works with the left/start drawer not the right/end one

Demisec answered 8/3, 2022 at 2:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.