I have an Activity
which uses the Android NavigationDrawer
.
When using only fragment
s (as usual), everything works perfect.
But now I want to use this drawer
on other activities of my app, and for some of them,
I don't want the main view to be a fragment
.
Question
The problem is, the onTouchEvent()
of the activity
itself (and the onItemClickedListener()
of a child ListView
for that matter) isn't called, because the drawer
consumes it.
Of course, I want it to be called:)
Needless to say, I would hope the answer will be simple (even a XML one), and hopefully not by extending the Drawer
class (unless that's what it takes of course).
More Info
The Activity's main layout is very simple, basically a ListView
and the DrawerLayout
on top of it (below in XML).
The Drawer
has one fragment
as it's childView
(for fragment navigation) and of course, the ListView
for the Drawer
Items.
I've seen many questions regarding (not exactly) similar issues, and the frequent answer was to use onInterceptTouch()
, requestDisallowInterceptTouchEvent()
on the DrawerLayout
, and on the Parent view (Activity
's main content) and even onTouchEvent()
(with False returned) on the ListView
of the Drawer.
Nothing seems to do the trick.
I read this link
and it does seem like using Intercept methods somewhere could be the answer. But how?
Please let me know if you need any code. But it's a very basic code/layout for this matter.
Thanks!
Apparently the answer is somewhat easy, although it does make you extend the DrawerLayout and do some thinking, and maybe will result in some strange results (using the LAST example, I haven't seen any, yet).
Anyway, related questions which looking backwards can help understanding the issue (will explain about the first one later on):
1. DrawerLayout prevents call of MainActivity.onTouchEvent()
2. How can I requestDisallowTouchEvents on Android DrawerLayout
3. Set drag margin for Android Navigation Drawer
Answer
First, please note that I put lots of examples here. If you just want the best one (for me), jump to the last one.
Secondly, if someone has enough reputation, please comment on the first link's question and put a link to this answer (it can help that guy).
Example 1
Well, basically, just extend Android's DrawerLayout and replace onTouchEvent() to this:
This solution will do anything except that it won't open the Drawer on slides, only menu clicks and the like. Besides, it forwards clicks so when the Drawer is open for instance, touching outside of it will NOT close it, but click on whatever is behind (e.g. a ListView). Le'ts try harder...
Example 2
Now, let's catch the open OR visible cases, to return true (and consume the action at the Drawer).
This solution is better, as it prevents clicks on behind the Drawer when the drawer is open or even visible (slide starts...). But touch-sliding it still doesn't work.
Example 3
Ok, so let's just split cases. Touches (MotionEvent.ACTION_DOWN) inside the Drawer's margin (area that Google desided to slide Drawer when touched at) will result in returning True to consume the action, and others will forward the event (return False).
Note that I used 30dp. That's what I found to be the margin (although in one of the links it is said to be 20....).
Well, the next example would of course be deciding what is, exactly, that edge (see in code above) value is, according to Android. We don't want to use a number that could change or whatever.
New Question
So now that first link should come handy. It "hacks" the Drawer code to get that Drawer edge/megin number. BUT, it didn't work for me, as those exact Field names could not be found.
I run mDrawerLayout.getClass().getField() which returns all the fields, but without any luck finding what we want. Anyone?
Last Example - Full Code
Ok, looking on example number 3, after understanding what exactly I did, we can make it faster by extending the onFinishInflate() method and save it as a global variable for this CustomDrawerLayout for later use. We can also put that first 'if' inside the second one to save some more work. OK here goes:
That's it for now! Hope it'll helps someone in the future beside myself, hehe....
I have a solution:
Set
OnTouchListener
on the screen layout (the first childview ofDrawerLayout
, normally) and transmit theTouchEvent
to a customGestureDetector
.So, you can do your own things in it. One more important thing: if you want to override
onSingleTapUp()
or something else, you shouldreturn true
inonDown()
to make sure that you can get the restMotionEvent
to makeonSingleTapUp()
work.and set it :
To add on to guy_m 's answer, here is my implementation for a drawer that opens from the right, includes constructors so that it is viewable in the layout editor and also takes into account when a user swipes from past the edge point:
}
While working on the same problem I was inspired by guy_m's answer and boiled down his proposals to the following solution.
Again it amounts to extending DrawerLayout and overriding onInterceptTouchEvent(). The logic is simple:
Whenever the touch event occurs off the drawer view (the slideable part), we return false. Then our DrawerLayout is out of the game when it comes to handling the event -- the event is handled by whatever view we put into the DrawerLayout at the respective position.
On the other hand, when the event occurs inside the drawer view, we delegate to super.onInterceptTouchEvent() to decide what to do with the event. That way the drawer will slide in and out as before on touch gestures happening on itself.
The following code sample is for a DrawerLayout whose drawer view is located on the right (android:gravity="right"). It should be obvious how to modify it to cover also the case of a left-placed drawer.