I have 4 buttons on an activity. I have set Touch Listeners for all the buttons.
Button1.setOnTouchListener(this);
Button2.setOnTouchListener(this);
Button3.setOnTouchListener(this);
Button4.setOnTouchListener(this);
All I want to do is to get MotionEvent.ACTION_DOWN and MotionEvent.ACTION_UP when I am moving my finger over the buttons.
I am getting these events when I am touching INDIVIDUAL buttons, but not when I move my finger from one button to another.
In this case, first button should get ACTION_UP message and the next button should get ACTION_DOWN message.
Kindly help.
There is a certain logic in such behavior of touchevents.
I think the best decision for you will be to set OnTouchListener to parent view of Button1, Button2, etc or override its OnTouchEvent() method. After that you will be able to send MotionEvent to child views (buttons in your case) manually when it's necessary.
My initial instinct is that you are sending all of the touch events to the same function, causing some type of bottleneck.
What if you seperate the touch handlers into four seperate functions like this - that way, all buttons have independent touch handlers and there is no collission by having them all using the same function to handle their collective events. Make a seperate "onTouchEventListener" for each button and have it look like this:
Button1.setOnTouchListener(button1Listener);
Button2.setOnTouchListener(button2Listener);
Button3.setOnTouchListener(button3Listener);
Button4.setOnTouchListener(button4Listener);
Here is how to do it from the Android docs:
// Create an anonymous implementation of OnClickListener
private OnClickListener mCorkyListener = new OnClickListener() {
public void onClick(View v) {
// do something when the button is clicked
}
};
protected void onCreate(Bundle savedValues) {
...
// Capture our button from layout
Button button = (Button)findViewById(R.id.corky);
// Register the onClick listener with the implementation above
button.setOnClickListener(mCorkyListener);
...
}
Since you're trying to capture a MotionEvent that involves all of the buttons, as opposed to just one, you will have to capture the MotionEvents in the parent view, then dispatch them to children buttons in the form of MotionEvent.ACTION_DOWN followed by MotionEvent.ACTION_UP.
I did something similar to make a multitouch keyboard out of a RelativeLayout containing many buttons. I basically overrided dispatchTouchEvent and kept track of each finger, sending ACITON_DOWN and ACTION_UP in place of ACTION_POINTER_DOWN and ACTION_POINTER_UP for secondary fingers to children.
It may be useful to look at the source of ViewGroup and see how it dispatches events to its children, and tweak the behavior to check when the finger goes out of child button bounds, and if so, send an ACTION_UP on the old button then an ACTION_DOWN on the new button.
Related
Let's assume there are all kinds of views on screen, is there any way to get every click/touch event on whole screen? And obviously I don't want to override every view's click/touch event since maybe I don't even know what views we will have.
I found that you can't even get events behind a Button.
Like I setOnClickEvent in LinearLayout which is the whole background of screen, then add a Button above this LinearLayout, when click this Button, Mr. Jon LinearLayout Snow knows nothing.
You can override this method in your activity.
#Override
public void onUserInteraction() {
super.onUserInteraction();
}
Every touch event on opened activity will fire this method.
I want to create an Android application to control a car remotely using wifi.
I discovered something pretty weird about ontouch events, if I keep touching the screen, event if I touch another button the event will call the first view, because I don't release the screen.
So, if I touch the FORWARD button, if I try to go left/right at the same time, I can't, because the event called is always forward if I don't relase the button. I have to stop touch the screen and touch left/right button to change direction.
How can I manage that?
Thank you.
// On click, go forward.
this.goForwardBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
goForward();
}
});
This happens when your Activity implements onTouchListener. You can define a view that does not cover the entire screen and let it implement onTouchListener.
I am trying to create view that sites underneath all others that will perform an action when 3 fingers are touched. These activities all have their own touches and swipes.
I have got this to kind of work by creating a class that extends linearlayout and intercepting touches. and adding this in xml.
But this is only being called when an item like button or view is a clickable or touchable surface and isn't becoming a touchable surface itself.
in
public class MyCatcher extends LinearLayout {
#Override
public boolean onInterceptTouchEvent(MotionEvent event) {
int action = event.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_POINTER_DOWN:
// multitouch!! - touch down
int count = event.getPointerCount(); // Number of 'fingers' in this
if (count > 3) {
doThis(mContext);
}
}
return super.onInterceptTouchEvent(event);
}
And in xml
<packagename.MyCatcher
....>
my normal layout
</packagename.MyCatcher>
So this code is working when an item that is touchable is touched but not becoming its own touch layer.
I have tried setontouchlister in the constructor with no luck.
Thanks for any help
EXTRA: When setting the touchlistener via onAttach I can get it to catch touches but I can't use event.getPointerCount() like normal as it's returning 1.
I'm worried this may take up lots of processing?/
Instead of a Layout, create a normal View and add it to your existing layout so that it spans the whole screen and lays "above" all other views (in z-order). Now it should get all touch events prior to all other views. Your onTouch... implementation should make sure to pass all touch events along to the other views (except if you want e.g. buttons not to work under certain circumstances, then do not pass the events along).
onintercepttouchevent()
Is called only whenever a touch event is occured. ie; touch event occurs only when a view item like button,textbox,etc having onclicklistener enabled is pressed . For your question you need to set the onclicklistener for the entire view.
I tried to understand how Android handle touch event and got a little bit confused. From what I understand touch event are send to the root view and pass down to the children.
I have a FrameLayout that is a container for Fragment.
First fragment view is a ScrollView, second one is some kind of Gallery (HorizontalListView) and the last one is also FrameLayout. Only one fragment in the layout each time.
What I want to do is to identify user swipes on the screen, for the app use. I want to count the swipes and do something after some number of swipes.
I tried to put a OnTouchListener on the top FrameLayout but it doesn't get called when the child is the ScrollView or the Gallery. I tried to return false and also true in the end of onTouch, but I get same result - it's never being called.
How can I do it?
I just want to "transparently" handle the touch events and passing them on like I didn't even touch them.
My understanding is that it actually goes the other direction. The Child views get their event triggered first (sort of). The root view get's it's dispatchTouchEvent() called, which propagates the event down to the children's onTouchEvent(), and then, depending on whether they return true or false, the parent's onTouchEvent() is called.
The normal solution for intercepting things like this is to override dispatchTouchEvent(MotionEvent ev) in one's activity like so:
#Override
public boolean dispatchTouchEvent (MotionEvent ev) {
// Do your calcluations
return super.dispatchTouchEvent(ev);
}
The documentation for this one is here. Note that you can also override that method in any ViewGroup (such as a FrameLayout, etc)
The problem is the the scrolling will intercept with touch event has set to the parent layout.
Can I keep the onTouch event with the scroll in ScrollView ?
This is a very tricky part. There is an overriden method from Activity which is: public boolean onTouchEvent(MotionEvent event)
This is the general method that interprets all the touch events from the whole screen. And you could say, "ok, I can implement this and I am good to go..". And here comes the difficult part on how android works.
As you know every View has its own onTouchEvent() method that you could implement in order to add some custom implementation. So which method will listen? The ScrollView or the Activity? It appears that these touch events go from the "inside" elements to the "outside" elements. I mean parent-child relations.
Another thing to take into account is that the onTouchEvent method returns a boolean. This boolean parameter determines whether the touch event should go one level up or it is handled by the current View. Meaning that if you have a CustomViewA that implements the onTouchEvent() and CustomViewB implementing its own touch event, and the A is a child in B then the touch event would go through A first and if it is not handled it would go to B.
So basically yes it could be done. It depends on what touch event you wanted to do.
So in our case, the ScrollView returns true when the touch events are a horizontal. The activity's touch event will be handled only if the ScrollView touch event is not handled by itself then you are fine. Otherwise you have to override and implement the on touch event of scroll view and in some cases you have to return false so as for the whole layout to implement it. Good luck with the last part. I started to implement a fling effect but came up with some difficulties so I have implemented a 2 finger move with scroll view in it and it works like a charm.
This is about a week of research and experimenting and it is an overview of what I came up with. if you find anything else please let me know. Hope it helped.