I am trying to understand what clickable in Android means. I have a simple Button subclass which overrides onTouchEvent() and also implements OnTouchListener.onTouch() (returns false to let the event bubble up to the view) and I noticed that the callbacks are called with MotionEvent.ACTION_DOWN (listener first, the view method later), and nothing more. I thought clickable = false disables touch events completely, but apparently not. What does it really do? How can I make sure the view doesn't get any touch events at all (setEnabled(false) seems not to work at all, events for ACTION_DOWN, _MOVE and _UP are fired unhindered).
Why are some touch events handled and other are not for clickable = false? I find it pretty surprising behavior and inconsistent - I would expect MotionEvent.ACTION_UP to be fired as well, but maybe click listeners should not be called. Any guidance?
Update With setEnabled(false) only the View.onTouchEvent method is called, the listener is ignored. Even stranger...
As I understand, setClickable is for calling the onClickListener when you click on it, and the actions like ACTION_DOWN, ACTION_MOVE, ACTION_UP are for handling finger events on the View within a OnTouchListener.
Related
I am using the default project template from Android Studio. When I swipe on the textView, the onClick event will get triggered. Is it the designed behavior or where did I do something wrong?
In my experience OnClick is triggered because when you put your finger on textView its ACTION_DOWN method gets called internally and after swipe when you remove your finger its ACTION_UP method gets called internally. So whenever these two combination gets called it calls the onClick method. So when you touch (ACTION_DOWN) the textView and swipe left/right and move your finger outside (without the ACTION_UP event) it won't get called because its ACTION_UP is not called.
PS. This is not the official definition/working of onClick... This is how it worked in my experience.
my solution is extending the parent viewgroup and examining motionevent in the onInterceptTouchEvent.
Why is the android onclick listener for any views which we listen using setOnClickListener() is not working as expected, I mean onclick similar to desktop mouse event, onclick should be fired when mouse DOWN and UP events are triggered at the same location, but in case of android, after ACTION_DOWN if I move a little and release touch, I still get onclick fired. This is causing some unwanted effect on my TextView, which has links.
Is it because there will be always slightest difference in up and down coordinates? the reason for poor implementation.
USE CASE
Suppose in onclick I need to toggle ActionBar visibility but I do not want that to happen when I swipe which again fire onclick. For I was hoping for a clean code using android inbuilt options instead of using flags around touch listeners.
The onClick method is called on the release (ACTION_UP).
If you want to track the DOWN and UP actions yourself you can use an onTouchListener instead (see http://developer.android.com/reference/android/view/View.OnTouchListener.html).
in my android application, I've made a view draggable with a OnTouchListener. This works still fine. The listener is set to a ListView. Now the problem is how to set the onTouch and the setOnItem(Long)ClickListener(s) at one time.
What I've already tried:
Set both listeners, the onTouch Event returns false. When I drag the ListView the OnItemLongClickListener Event is fired. -> Can drag the view, but a Dialog appears.
Set both listeners, the onTouch Event returns true. -> The item click listeners are never fired
Set both listeners, the onTouch Event returns false, but when the X-difference is big enough (between startX and nowX) for a drag gesture then it returns true. So what I thought
was: It returns false for a click. But when the view will be dragged it returns true, so the listeners are not fired. -> On each drag the OnLongItemClick event is fired - even when I
lift the finger from the touchscreen. Obviously an OnLongItemClick event is detected in the return false time, and when the OnTouch listener returns true it still runs - and is not breaking.
How could I solve this problem? My Idea was it to break the OnLongItemClick event when a drag is recognized. But I've just don't have founded a way how to do so.
If you need a even more complicated explainaiton for #3, please leave a comment.
Thanks a lot.
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.
I implemented OnTouchEvent ( I need to react on Action.MOVE and Action.Up ) and OnClick, but it never enter in OnClick. OnTouch steals evemt. How to solve this ? I need on touch because Actoion.Up and Action.Move. I have added clickable, focusable and focusableInTouchMode to true.
If you don't want the TouchListener to consume events on certain views, you need to make sure that you return false for those specific cases in your onTouchEvent implementation. Returning true at any point will consume the event and not allow other actions to be performed based on it.
HTH
When you need both click and touch events on the same view, it's best to use a GestureDetector.