2

In our application we have a custom view (that extends ImageView) and in it we handle the touch events to record data. I wanted to add context menu functionality to this view and followed the guidelines in the official Android documents.

The onTouchEvent code works fine by itself. The context menu code also works fine. However, if I add them both, the context menu code stops working. I found out that with both pieces of code added, onCreateContextMenu is never called, therefore context menu is never displayed.

According to my interpretation of the Android documentation, returning false from onTouchEvent indicates that the event is not consumed, so it should be used for further processing. For some reason, it is not happening here. I would appreciate if anybody can tell me what I am missing. BTW, the target is Nexus One running 2.3.4 ROM.

Here's the code for the onTouchEvent in the custom view:

public boolean onTouchEvent(MotionEvent event) 
{
    switch (event.getAction())
    {
        case  MotionEvent.ACTION_DOWN:
            // Add event coordinates to an arraylist
            break;
    }

    return false;
}

Thank you in advance for any help.

alokoko
  • 1,405
  • 4
  • 21
  • 35
  • Can you also post the longclick code? – stk May 30 '11 at 22:40
  • You mean the code I tried per the comment from Snicolas? It is very simple: `@Override public boolean onLongClick(View v) { openContextMenu(myView); return true; }` – alokoko May 31 '11 at 09:31

5 Answers5

2

Elaborating on hackbod answer, you should probably have as last method statement return super.onTouchEvent(event);.

I guess that if you don't process the event, and if you don't invoke the default View behavior, than no one will do anything, and nothing will happen.

The point of return value might be for example to invoke some ancestor' default behavior, and let the derived class know if the ancestor processed the event or not.

After doing some search on Android Developers, referring to the topic override an existing callback method for the View here it says :

This allows you to define the default behavior for each event inside your custom View and determine whether the event should be passed on to some other child View.

Hence the main idea behind the return value is to let Android know whether the event should be passed down to child Views or not.

HTH

Edit:

Regarding the "directions" you mention in your comment, generally speaking (i.e. not only on Android) the UI event handling process goes on something like this:

At some point your derived custom control receives the event. In your event hook implementation, it's up to you whether to involve your ancestor's behavior or not. That's all you got regarding the class inheritance direction.

Then, there's the other direction, the one related to the UI controls hierarchy. Your custom control might be contained in one larger control container, and your control might as well contain other inner controls (textboxes, buttons, ...). Regarding this direction, if you declare not to process the event (returning false) then the UI event handling mechanism will pass the bucket to the containing (?) control (think the one on the background of yours).

superjos
  • 12,189
  • 6
  • 89
  • 134
  • Yes, hackbod's suggestion works fine. I am trying to understand how it works. I read your link and the [Handling UI events subtopic](http://developer.android.com/guide/topics/ui/ui-events.html). There it says "[...] call event handlers first and then the appropriate default handlers from the class definition second". Now I am confused about in which direction UI events are going: First doc mentions child views, while this one says "event handlers first and default handlers second". It seems I need a good tutorial that explains how this mechanism works. Would you happen to have a link for one? – alokoko May 31 '11 at 10:00
  • No I'm sorry, I do not have such a link. But I edited my answer and tried to clarify my thoughts on the _directions_ you mentioned. – superjos May 31 '11 at 18:45
  • Thank you very much for your detailed reply, I really appreciate it. I have one more Q if you do not mind: In your edits, you mentioned invoking ancestor behavior and event handling mechanism passing the message to the containing control. This all makes sense. In the original reply you had quoted the Android doc w.r.t passing the event to child views. What I am trying to grasp right now is how it is possible for other child views (whose child, BTW?) to receive an event from my control. Does the event go up to the parent and then the parent notifies all its other child views about this event? – alokoko May 31 '11 at 19:10
  • Whether you want to _go up the class hierarchy_, invoking default behavior, it's up to your derived class implementation. The other views that might receive the event, if you declare you not to consume it, are the ones related to your view depending on the UI hierarchy, i.e. the hierarchy defined in your XML layouts. In this context, child or parent relationship has nothing to do with the class inheritance, but it refers instead to a container/contained control relationship. Like in `` – superjos May 31 '11 at 19:41
  • Thanks once again for helping me. I understand the class hierarchy part. Let me see if I understand the UI hierarchy part correctly using your example: If I receive a touch event in my `CustomControl` and return false to indicate I have not consumed it, does `LinearLayout` get it and notify `EditText` and/or `Button`? As an FYI, in my particular case, it was `MyImageView extends ImageView` and I was trying to get the long click->context menu functionality through `ImageView`'s implementation while keeping track of the touch events through the `MyImageView` class. – alokoko May 31 '11 at 20:05
  • Regarding the UI hierarchy part: the first UI control that receives the event is the top one on the `Z-layer` found right under the finger touch/click (or mouse click on a PC, for what that matters). If that control does not consume the event, than its container, its containing control, receives the event. And so on up to the largest container, containing the whole _screen_. So in the example, if the event goes first to `CustomControl`, which does not process it, then the `LinearLayout` should receive the event. The two sibling controls (EditText and Button) will not receive it. – superjos May 31 '11 at 20:21
  • If I'm wrong on this, then the UI hierarchy processing would be the other way around: from the largest container, down to the smallest control under the finger touch/click. But still, the sibling controls are not involved in this. It's all on a straight _descendants path_. – superjos May 31 '11 at 20:25
  • If the UI processing is from the control under the touch to the largest container, then it explains why my code isn't working: The code gets the touch, doesn't invoke ancestor behavior, returns false, event is sent to container (FrameLayout) that does nothing with it. However, if the UI processing is the other way, then I have no idea how such processing could possibly work. In any case, I am changing the design so that the app no longer has a context menu. You have been very helpful in making me understand parts of this system. Thank you for your time and effort. – alokoko Jun 01 '11 at 10:05
  • You're welcome. Sorry for not being definitely clear on that final bit. It's "just" a matter of doing some research on usual UI update mechanisms ... which I haven't done recently :) – superjos Jun 06 '11 at 22:41
1

Do not register for context menu in OnCreate(), do it in onTouch() before return true;

registerForContextMenu(View v);
openContextMenu(View v);
return true;
Rob
  • 26,989
  • 16
  • 82
  • 98
1

You could call, from your long click listener,

openContextMenu(View view)

http://developer.android.com/reference/android/app/Activity.html#openContextMenu(android.view.View)

Snicolas
  • 37,840
  • 15
  • 114
  • 173
  • 1
    Yes, but long click listener does not get called as long as the `onTouchEvent` code is there. – alokoko May 30 '11 at 18:55
0

I encounter similar problem recently. When I enable long clickable in RecyeclerView's child, the ACTION_DOWN event can't not be received in RecyclerView's onTouchEvent.

If I changed to RecyclerView's dispatchTouchEvent, I would works. The ACTION_DOWN event can be received.

alijandro
  • 11,627
  • 2
  • 58
  • 74
0

Returning false tells the parent that you didn't consume the event. The default implementation of View implements touch handling for that view; if you want that to execute, you must call super.onTouchEvent(event);

hackbod
  • 90,665
  • 16
  • 140
  • 154
  • Thank you for replying. Can you clarify "The default implementation of View implements touch handling for that view" a bit? Do you mean that even if I return `false`, the touch handling code for the parent does not run? If so, what is the point of return values in `onTouchEvent`? – alokoko May 30 '11 at 18:59