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.
Related
I have four ImageButtons in my app.
Three smaller buttons can be either shown or "hidden" below the bigger button. I hide buttons using rotate and translate animations.
The problem is:
OnClickListener's onClick method always gets triggered no matter a smaller button shown or not.
I mean, when smaller buttons are "hidden", touching the place on screen, where one of the smaller button resides when shown, triggers onClick method.
It looks like Android OS does not take actual placement of the button into account when deciding whether it should trigger onClick method or not.
How can I overcome the issue?
I want onClick method to be called ONLY when there is a button below my finger.
EDIT:
All suggested workarounds rely on hiding the button. This doesn't help at all. The onClick method gets called for INVISIBLE and GONE buttons too. I checked this in debugger.
Looks like you are going for an Arc menu. Why not use the awesome implementations of Siyamed and DaCapricorn, instead of re-inventing the wheel?
Did you set your click interface your activity and implemented onClickListener? If so you need to separated your buttons by setting if conditions like if(arg0 == button1) for all the buttons.
The issue was caused by the fact that tween animations (the original animation framework) animate the pixels, not the touch zones of a widget.
I have replaced tween animations with property animations and now everything works like I expect it to work.
Setting
btn.setVisibility(View.INVISIBLE);
doesn't call onClick method where buttons are not visible. I have tested it. So you might be registering onClick listener in unnecessary views.
Try to set the listener using the property onClick of the button in the layout.xml (for example
android:onClick="onClickButtonCamera"
and then declare a public function with the same name like:
public void onClickButtonCamera(View view) {
//some stuff...
}
I allways use it and the function is never called when the buttons are hidden.
I hope it helps you.
i think there are three ways to solve this issue.
1) if you are setting onClick Listener then set it null when you hide buttons and set listener when you show them.
2)Add a checking in onclick for each button about their visibility simply return; the function when button's visibility is not VISIBLE(use the function button.getVisibility() != View.VISIBLE)
3)Last one not sure, usually setting gone as visibility will protect it from clicking.
I'd suggest setting the button visibility to GONE after completing the animation.
UPDATE:
Another suggestion is to have a button that is not animated (for which the problem should not happen) and an image (graphically identical) that is animated after the button is hidden. The image should not receive any clicks, under the big button or not, and the real button should not receive clicks when hidden.
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 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.
I use a view switcher to switch between views in a way that is similar to standard activities switching in a task. For example, the current view in the switcher might have a button that, when clicked, initiates the view switch: the current view, which is now obsolete, slides out, and is replaced by the new current view, which slides in.
The animated switch is fine only for one thing: I cannot find a correct way to tell the sliding out view to stop processing user events, like touch events. So what happens is, if done fast enough, and it doesn't have to be that fast, the user can click on the button that initiates the view switch more than once, which is bad. Once a click (or any user action) has initiated a view switch, I would like to invalidate and ignore all other user events on the sliding out view.
Is there a clean, standard way to do so? I've tried setEnabled(false) on the sliding out view, but it seems click listeners in child views are still handled afterward. The thing I want to avoid is looking for all event handlers and adding verification code that ensures that nothing is done if the view is actually sliding out.
I had a similar problem and want to share my solution. I override the Activity.dispatchTouchEvent method as noted here. In doing so I intercept all touch events before they are dispatched to the other views.
public boolean mDisplayBlocked = false;
#Override
public boolean dispatchTouchEvent(MotionEvent pEvent) {
if (!mDisplayBlocked) {
return super.dispatchTouchEvent(pEvent);
}
return mDisplayBlocked;
}
In your click listener, before you initiate a view switch, I believe you should be able to disable the listener.
I imagine other UI interactions will still be possible though. Perhaps you need a masterDisable method, which will disable all UI interactions on that View, which you can call before you make the view switch.
There is no method to tell a parent to disable all of it children's events. And also, calling setEnabled(false) on a parent does not disable it's children.
Probably the easiest way to do this is to call setEnabled(false) on the button.
May be, If you set the visibility to GONE for the child controls of the fading out view, you can check the same in the listener and handle events only for the visible views.
Well, it was painful, but I think I finally found the right way to achieve what I wanted, and you really have to find out how the Android API wants you to do it. So here is how I manage the child view that is sliding out:
childView.startAnimation(animation);
parentView.removeView(childView); // makes childView a "disappearing child" of parentView
That may seems strange, but when you do that, childView is still drawn in its parent, even though it is not "physically" there anymore (it doesn't receive user inputs anymore, which is the behavior I was after in the first place). Hence, childView becomes a "disappearing child" of parentView, a very special case implemented in ViewGroup. And when the animation ends (through AnimationListener), you must do:
parentView.clearDisappearingChildren();
otherwise parentView will still draw the pixels of not-animated-anymore childView.
Note that the first thing I tried was:
childView.startAnimation(animation);
And when the animation ended:
parentView.removeView(childView);
Even though that way of doing seemed natural to me, all hell started to break loose! I started getting NullPointerException deep in ViewGroup.dispatchDraw. All of this because AnimationListener.onAnimationEnd was called during the execution of ViewGroup.dispatchDraw, and changing the list of child views is a very bad idea at that point...
I've got a LinearLayout with a bunch of buttons on it. This panel is always hidden unless a menu item is chosen.
When the LinearLayout is shown, I want to detect if the user clicks anywhere outside of the panel so that I can hide it again. Is there a way to do this, maybe with detecting focus changes?
I've tried to add an OnFocusChangeListener to the LinearLayout itself (and called setFocusable(true) on it), but the focus change listener never gets called. Furthermore, I'd have to be able to detect if the LinearLayout or any of its children lose focus.
Try this:
Step #1: Have the LinearLayout watch for touch events, and consume them
Step #2: Have the thing under the LinearLayout watch for touch events -- if it gets one, you know it wasn't from the LinearLayout, so you dismiss the LinearLayout and consume that event, then perhaps unregister for touch events (or just only pay attention to them if the LinearLayout is on-screen)
Step #3: There is no step #3...I think