From the Event Handling Framework of android I find that this is its mechanism:
Event get catch if the user interacts with the device screen
It is stored in a MotionEvent Object.
Android gives this Object to the Activity dispatchTouchEvent() method.
This method dispatch event to the listener of activity . if they did not consume it, it go to the biggest parent of activity, for example, linear layout.
And this mechanism that every dispatch method, dispatch MotionEvent to the listener of view and if those did not consume it to a child of view.
After this MotionEvent object reaches the last view in the hierarchy it goes up in the OnTouchEvent() method of child and goes higher to OnTouchEvent() of a parent till it reaches to OnTouchEvent() of activity.
If I understand this correct I just want to know what is the purpose of going up of the MotionEvent in OnTouchEvents? We could handle every form of event from a simple click to custom gesture till the MotionEvent object reach the last listener of the last view in the activity. What's the use of OnTouchEvent() method and why it must go up to the activity?
Related
I need to create a click event, that's not being consumed, so that an underlying adapter receives the touch event.
I cant use an OnClickListener, because that would consume the event.
I tried my best with OnTouchListener, but if I return true the event gets consumed and if I return false the listener only registers ACTION_DOWN events.
How can I react on a click, but if its not a click the adapter will receive the move?
EDIT:
I'm using a lorentzos.swipecards SwipeFlingAdapterView, which uses touch-move-events. I put a layout over half of the view of the items of the adapter, which need to react on click events. But I either can't implement the click event, since I can't catch two events in a row without consuming them, or I can't have the SwipeFlingAdapterView react on the touch-move-event, since I, well, consumed it in the click event.
Don't know what sourcecode to share, since I tried many different ways and nothing works.
I know this got asked often, but all solutions(, I found,) don't work for me.
What I have is a CardView with an OnClickListener making a Toast (#toast1).
Inside the CardView there are multiple views as also a WebView.
As mentioned elsewhere, to pass through the click through the WebView to the CardView I have done following:
Set android:clickable="false" in WebView XML
insert following under CardView.setOnClickListener(...)
WebView.setOnTouchListener( (view, event) -> true);
I also replaced the lambda with an anonymous method, to see if its just this. No change.
What happens now is:
At the border and over the other views, the clickListener is triggered and the toast appears
Over the webView the clickListener isn't triggered.
Also put a toast (#toast2) in touchLstener of WebView before returning true, and it gets triggered.
What I expect:
Click will passed through WebView
With #toast2 added: First show #toast2 then #toast1
What is a bit confusing, that in documentation of OnTouchListener, the return is following:
True if the listener has consumed the event, false otherwise.
For me that means:
true: Don't pass click to below views, as listener consumed it
false: Pass click to below views, as listener didn't consumed it
But setting to false didn't change anything.
First of all I would suggest you to get familiar with android touch handling system - you can find a really good description in this answer. To sum it up: touch event propagation starts on top level of hierarchy, but actual handling of the touch event starts on the lowest level of view hierarchy. As for solution of your problem I may suggest to sublcass the parent of your WebView and override onInterceptTouchEvent in the following way:
#Override
public boolean onInterceptTouchEvent(MotionEvent e) {
return true;
}
This will instruct this parent view to intercept all touch events that would otherwise go to its children views, thus limiting the first level of touch processing to this view.
my on Touch() method never gets called, even if I touch the screen, do you know why?
#Override
public boolean onTouch(View arg0, MotionEvent ev) {
Log.v("drawing", "Touched");
return true;
}
and here the class
public class Run extends Activity implements Drawer, OnTouchListener{
Currently in your code u didn't set any setOnTouchListener to any view or layout.
for example, your touch method has to work on, add the setOnTouchListener for ur xml layout in ur code.
AbsoluteLayout mainLayout // i'm using absolute layout in xml , change according to ur xml main layout
mainLayout = (AbsoluteLayout) findViewById(R.id.container);//reffer the id
mainLayout.setOnTouchListener(this);//set listener
now touch the screen and check the log ..
onTouch in Activity will almost never be called, except if none of the Views consume the touch event.
Instead, if you really want your Activity to handle touch events, listen for touch events in onInterceptTouchEvent(MotionEvent).
An interesting talk on this: Mastering the Android touch system.
in iOS world, there's a concept of touchUpInside, touch started within a view and user lifted a finger within a view bound.
I see touch vs click (event listeners) in android, and I'd like to know the difference between them.
Touch events are much more basic. There's many varieties. The most common being:
DOWN: The user touch the item
MOVE: The user shifts around the item after touching it
UP: The user stops touch the item
CANCEL: The user shifts off the item but is still touching the screen.
In Android, a click event is a composite of touch events. In the case of click it's both DOWN and UP action. There are others that can be found in a GestureDetector. Fling for example is a combination of DOWN, MOVE, and UP in a fast motion that signifies the user swiped the finger really fast.
EDIT:
Clarification on how Android handles the true and false in onTouchEvent().
It's not very well documented, but the way the Views work in Android is that when you touch a View, it will send that touch event from the parent view to all children views. Each child will then send the event to it's children. This is done in the dispatchTouchEvent() method.
When a parent View receives false from the child's onTouchEvent() method, it will no longer send touch events to that child. Meaning that when you're view returns false in onTouchEvent(), your View is really says:
I am done processing touch events and all of my children are done as well.
90% of the time, in onTouchEvent() you would do return super.onTouchEvent() to return the touch values of all the children in the View.
So let's look at your click example. Here's one way to do it in which you return false on a DOWN event, but true on an UP.
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
return false;
case MotionEvent.ACTION_UP:
return true;
break;
default:
return false;
}
}
In this case, the parent of this View will receive false immediately. After which, it will stop sending touch events to this View because you said it was done.
Here's another way:
boolean mPossibleClick = false;
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mPossibleClick = true;
break;
case MotionEvent.ACTION_UP:
if(mPossibleClick) {
// UP event immediately after DOWN. Perform click action
}
default:
mPossibleClick = false;
}
return mPossibleClick;
}
It's rather crude, but basically here's what will happen. When the user first touches it, you will receive DOWN which will return true. If the user lifts the finger, it will perform a click action after which will return false because the event is done. If the user moves his finger or any other action is performed, it will return false and the click will be nulled out.
That last one is not the best way to implement a click, but I think it illustrates what I'm trying to say. In real life, move events are extremely common if even for a couple pixels.
onClickListener is used whenever a click event for any view is raised, say for example: click event for Button, ImageButton.
onTouchListener is used whenever you want to implement Touch kind of functionality, say for example if you want to get co-ordinates of screen where you touch exactly.
Definitions:
onClickListner: Interface definition for a callback to be invoked when a view is clicked.
onTouchListener: Interface definition for a callback to be invoked when a touch event is dispatched to this view. The callback will be invoked before the touch event is given to the view.
Details:
onClickListener: http://developer.android.com/reference/android/view/View.OnClickListener.html
onTouchListener: http://developer.android.com/reference/android/view/View.OnTouchListener.html
refer to the response of PH7
which one is better to use?
It really depends on your requirement.
onTouch gives you Motion Event. Thus, you can do a lot of fancy things as it help you separate state of movement. Just to name a few
ACTION_UP
ACTION_DOWN
ACTION_MOVE
Those are common actions we usually implement to get desire result such as dragging view on screen.
On the other hand, onClick doesn't give you much except which view user interacts. onClick is a complete event comprising of focusing,pressing and releasing. So, you have little control over it. One side up is it is very simple to implement.
do we need to implement both?
It is not necessary unless you want to mess up with your user. If you just want simple click event, go for onClick. If you want more than click, go for onTouch. Doing both will complicate the process.
From User point of view, it is unnoticeable if you implement onTouch carefully to look like onClick.
for more details : refer this and this
I am using table layout to display data, but i want it to behave like list items
(ability to select, when select change background, when click, having hover effect, click able) for that purpose i am using following listeners
OnClickListener(to perform action)
OnFocusChangeListener(To change background color)
OnTouchListener(to focus specific row)
Now problem is when user touch any item it get focus first and then have to touch again to fire onclick event, to fix this i made a change and ontouch i fire action on specific to row.
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() != MotionEvent.ACTION_UP){
v.requestFocus();
int viewId= v.getId();
handleEvent(viewId);//Switch cases to perform row specific actions.
}
return false;
}
now if user touch the row event get fired that works perfect, But one more problem rises here when even user want to scroll down the data via dragging finger onto the screen ontouch event get fired.... and action automatically performed although user think it will scroll down the screen.
I don't know if this solution is applicable in your case, but maybe you can do like this:
Let's assume that user clicked your item (so probably you will get sequence of three events to your OnTouch() method: ACTION_ DOWN, ACTION_ MOVE (not necessarily) and ACTION_UP. Now you can react accordingly.
If it's ACTION_DOWN, you can save x and y coordinates.
If it's ACTION_ MOVE, take its x and y and calculate the distance from corresponding ACTION_DOWN. If it's longer than some assumed value, then make the scroll and set the flag indicating that items were scrolled.
If it's ACTION_UP check your flag. If items were not scrolled, fire your action and clear the flag.
Probably calculations is not what you should do in ACTION_MOVE event, because it should be fast, but give it a try.
Regards!