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.
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).
You could call, from your long click listener,
openContextMenu(View view)
http://developer.android.com/reference/android/app/Activity.html#openContextMenu(android.view.View)
Do not register for context menu in OnCreate(), do it in onTouch() before
return true;
registerForContextMenu(View v);
openContextMenu(View v);
return true;
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);
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.
Related
I am working on android surface view with touch events.
Below is the code I wrote for surface view to handle touch events.
As shown in the image, I logged when the listener is called.
Then in when clause I handled ACTION_DOWN and ACTION_MOVE events.
However, when I touch the view, not only the when clause can't catch the event
but OnTouchListener is even not called too.
I also don't understand why trues in when clause are not used.
I wrote those expressions to tell OnTouchListener to return true.
Can anyone help me?
+) I figured out that my surfaceview doens't call onClick() too.
particleSurfaceView.setOnClickListener{ Log.d("sv", "click") }
never logs
Try making the touch listener always return true. If you ever return false, you stop getting notifications for that whole gesture / touch.
Well, it was Android Studio problem..
Touch event works but only the logging didn't work.
I have no idea why but after relaunching the Android Studio, it works.
I am creating a custom Android component that needs sometimes to consume the onBackPressed event (e.g. there's a popup menu inside the custom ViewGroup, if it's showing, the back button event closes it and is consumed, otherwise it's ignored). Is that possible? Can I intercept this event from inside my ViewGroup subclass and how?
Edit:
I tried overriding onKeyPreIme as the Android documentation implies, the method is never invoked from within ViewGroup.
#Override
public boolean onKeyPreIme(int keyCode, KeyEvent event)
{
return true;
}
In the onKeyPreIme documentation it says:
Handle a key event before it is processed by any input method associated with the view hierarchy. This can be used to intercept key events in special situations before the IME consumes them; a typical example would be handling the BACK key to update the application's UI instead of allowing the IME to see it and close itself.
The reason why onKeyDown or onKeyPreIme are never invoked is because the ViewGroup does not have focus.
The solution was to request focus in the ViewGroup subclass' constructor:
this.setFocusable(true);
this.setFocusableInTouchMode(true);
this.requestFocus();
onBackPressed belongs to Activity and views/viewgroups are something placed inside Activity. So technically, you cant get this done. However, you may use some kind of observer/observable pattern to pass any kind of information to your views.
Or perhaps try using onKeyDown event inside your view class and track the back key event code.
Is there a way in Android where an android application when active will catch and process all key events (and maybe touch events) before they are delivered to the actual view which is supposed to be handling it?
I know that we can have onKeyDown or similar method in Activity to handle the keyevent, but it is fired only if none of its child views handles it internally.
These view are usually ListView, GridView, ScrollView, etc..
I want to find a way that my keyHandler method is called before that keyEvent is delivered to these views.
Implementation in my keyHandler will be very simple. It will just play a tone upon each event, just like keypress tone, and then forward it to be handled the way it was meant to be by those views or Android framework.
Want to know if its possible beacuse I don't want to write onKeyListener to each and every view in every activity as I have lot of activities and lots of views and it will just become difficult to write the same code everywhere. If there is a way, i can implement that in BaseActivity and derive all my activities by that and go on my way of having default key handler.
I don’t try it myself but I think this one will help you: (just scroll a little bit down to the method mentioned in the text)
Input Event: Event Handlers - Activity.dispatchTouchEvent(MotionEvent)
Looks like this is the chance to catch events before they get to the window. Read the detailed Description here.
In Android, I'm trying to capture user touches as well as User long-touches. I have an Activity and in it I override the onTouchEvent() method to handle a variety of screen touches.
I'm trying to incorporate "Long Presses" into my repertoire of User Interface choices.
I can't find a Activity.onLongTouchEvent() for me to override.
My application also has a SurfaceView and I see that I can do this:
sv.setOnLongClickListener (new View.OnLongClickListener()
{
#Override
public boolean onLongClick (View v)
{
SendAToast();
return false;
}
});
When I implement that code, it works exactly like it should.
However, now my onTouchEvent() code is never called even when I don't touch the screen long enough for it to be a "Long Press".
Is anybody aware of a way to get these two bits of code to work together?
Edit:
After I posted this, a co-worker showed me the "OnGestureListener" interface. Here's an example:
http://www.ceveni.com/2009/08/android-gestures-detection-sample-code.html
I use the interface to capture long presses, and it even provides the screen coordinates to work with (which the OnLongClickListener does not). So, it seems to do the trick.
Why this function not automatically part of the Activity? It sure seems like core functionality to me.
I would move the on touch stuff into the view's onTouchEvent instead of the Activity.
I put a list view inside a linearlayout,and I want to override onkeydown() method in ListView
,and I don't control the focus, just change some variables in onkeydown(),I want system do as if I haven't override the onkeydown method.what should I do?return false? or return super.onkeyDown()?.It will be very nice for any help. thank you in advance.
there are three listviews,and a b c are three item of listviews. when c is focused, when I press left arrow on keybord, then a get focus by default. And I want the first item in listview2 get focus how can I do?
ntc is not exactly correct. OS does not use reflection to get your base class' handler.
If you return false, you explicitly tell OS that you do not want to handle this event; OS calls the View's parent handler then (as your test shows); this happens until event got handled or top View is reached.
If you call super.OnKeyDown() you allow your base class to process event. Note that it's a base class' handler serving same view, not parent view; don't confuse here.
So, using one or the other depends on your view's behavior desired.
I supose in your case you need return super.onKeyDown();
super.onkeyDown()- this puts the burden on super class to handle the onKeyDown event by your own wish (You explicitly say to handle it). when you return false, android assumes that you have not handled the onKeyDown event and super.onKeyDown() gets called by default (without you calling it).