27

I have followed the tutorial Navigation Drawer and everything works like a charm except for a small glitch. I'll try to explain it as much as possible, and if it still isn't clear, I'll try to upload a video of the problem.

Problem happens when trying to open the drawer and only when opening, and only happens sometimes, not always. That is when I start to open it it glitches and freezes with about 4 millimeters open, and always the same distance. It then would not continue opening nor close back if I move my finger back, when I let go, it closes.

Please note:

  • I have tried it on multiple devices (Nexus 7, Nexus) and virtual devices as well, problem persists.
  • Issue replicated using the example provided by Google. (Youtube Link)
  • Issue presented with my app. (Youtube Link)
  • I managed to replicated the issue once but only once in Gmail app (which I believe uses the same implementation), however much more frequent with my app and the sample app.
  • I noticed that the glitch happens at the same distance of which the drawer opens if you just click the edge of the screen, as in it freezes after initial open and never drags.

Any pointers would be appreciated.

LuckyMe
  • 3,820
  • 2
  • 27
  • 35
  • 1
    Can you please attach a screenshot? – PravinCG Jul 27 '13 at 09:11
  • Does it happen if you open the menu by sliding from the border or by pressing the icon (assuming you have implemented this feature) or in both cases? Have you checked the logcat for any kind of exceptions? I've never seen something like this and I tested round about 10 devices. Which version of the support library are you using? **p.s.**: Does this effect also appear with the sample app? (see http://developer.android.com/training/implementing-navigation/nav-drawer.html) – Trinimon Jul 27 '13 at 09:30
  • @Trinimon Happens only by sliding. Logcat doesn't present anything. Was using the previous support library, and just did the update that was released lately and it still happens (Version 18). I have added a video to the original question, if you want to check it out. – LuckyMe Jul 28 '13 at 06:22
  • I could constantly notice the following logcat output if, and only if the glitch appeared `D/InputEventConsistencyVerifier(870): TouchEvent: Source was not SOURCE_CLASS_POINTER. D/InputEventConsistencyVerifier(870): in android.widget.LinearLayout{40d10590 V.E..... ......I. 0,0-320,359} D/InputEventConsistencyVerifier(870): 0: sent at 58488550000000, MotionEvent { action=ACTION_CANCEL, ...` ... however, I couldn't find anything helpful to resolve this issue :( – Trinimon Jul 29 '13 at 10:09
  • I noticed that the glitch happens at the same distance of which the drawer opens if you just click the edge of the screen, as in it freezes after initial open and never drags. – LuckyMe Jul 29 '13 at 10:18
  • Worked for me:http://stackoverflow.com/a/18591274/1526043 – Perry_ml Nov 11 '13 at 21:00
  • The easiest solution of this bug is here: http://stackoverflow.com/a/20016088/1444191 – Slava May 03 '15 at 22:50

2 Answers2

27

I researched the code of DrawerLayout and found the next issue: When we touch the edge of screen there appears small (20*density px) part of the drawer (it makes moving drawer easier). It doesn't appears immediatly, but after a certain interval (160 ms) of time. It is realized by postDelayed.

The drawer can be in several states: IDLE, DRAGGING and SETTLING. If it was in the DRAGGING state, it cannot return to this state anymore with the same pointer and edge (because there is a condition: mEdgeDragsInProgress[pointerId] & edge) == edge which doesn't allow to drag the edge which have been dragging already).

So in some cases the drawer have moved to the state DRAGGING already when delayed Runnable is executing. This delayed action opens drawer for 20*density px and change state of drawer. So drawer cannot be moved anymore (because it cannot return to the state DRAGGING).

There is a code for cancelling delayed action (which opens drawer), but this code in the method onInterceptTouchEvent, which is called only once (because it returns false). I think this code should be in the method onTouchEvent.

Unfortunatly I didn't find any way to cancel delayed event (because it has private modifier and I can't get it). So only one way I found: copy the source code of DrawerLayout to my project and make this small change: copy

case MotionEvent.ACTION_MOVE: {
            // If we cross the touch slop, don't perform the delayed peek for an edge touch.
            if (mLeftDragger.checkTouchSlop(ViewDragHelper.DIRECTION_ALL)) {
                mLeftCallback.removeCallbacks();
                mRightCallback.removeCallbacks();
            }
            break;
        }

from the method onInterceptTouchEvent to the method onTouchEvent.

esentsov
  • 6,372
  • 21
  • 28
  • Great research, props for taking it to the next level. Just a follow up, so the `DelayedRunnable` when executed changes the state to `SETTLING` then `DRAGGING`? Or just to `DRAGGING`, but then it glitches because the state was being changed from `DRAGGING` to `DRAGGING` once again? – LuckyMe Aug 07 '13 at 02:14
  • 1
    As I understand, state `DRAGGING` - `drawer` follows finger, state `SETTLING` - `drawer` moves with the constant speed, e.g. when we release it in the middle, it continues to move to close or open). `DelayedRunnable` changes state to `SETTLING` (because it is just animation, `drawer` don't follows finger). – esentsov Aug 07 '13 at 03:33
  • 3
    Another workaround is using android:clickable="true" in main content FrameLayout. http://stackoverflow.com/questions/18044277/android-navigation-drawer-bug-using-the-sample – Cheok Yan Cheng Feb 16 '14 at 12:30
  • @esentsov I might have the same problem. The first time I open the drawer it is opened in steps, after that everything is fine and smooth. I tried implementing what you said but I don't know who mLeftDragger or mLeft/RightCallback are. Could you take a look here http://stackoverflow.com/questions/33713720/drawerlayout-opens-kind-of-in-steps-the-first-time ? Thank you. – Bogdan Daniel Nov 24 '15 at 23:37
1

There is no error in drawerlayout file. Just add a ScrollView as the parent or root view to the content.xml(setcontentview file) file and tools:context=".MainActivity"

  • 1
    This question already had an answer which was accepted - having looked at the other answers, you should really only submit a late answer when you feel your answer adds a lot of value (for instance using the most recent utilities/libraries seeing that the question is 3 years old). – ishmaelMakitla Aug 30 '16 at 20:41