How to detect swipe for parent view when have multiple child? - java

I have a custom calendar layout that forms by multiple Linear layouts. when I set OnTouchListener to the parent view. It's not working because they are filled with child view. and I can't add the listener to each child view because It's a lot to set. Any solution that can solve this problem?

Turns out intercepting touch events is not as simple and straightforward as the guide would have us believe. To properly handle touch events in the ViewGroup, you'll need to override both onInterceptTouchEvent() and onTouchEvent() (if you don't want your child views to get the touch events as well).
The reference docs for onInterceptTouchEvent() explain this in a much cleaner manner than the guide. Here's an article that has the relevant code along with descriptions.
TL;DR - Once you intercept the touch event in onInterceptTouchEvent() and return true, the following touch events are sent to onTouchEvent() of your parent viewgroup. If you return false in onInterceptTouchEvent(), the following touch events are sent to the onTouchEvent() of the child views which you can continue to intercept in onInterceptTouchEvent().
You need to override onInterceptTouchEvent() in your custom calendar layout and do your touch handling there. Refer to the official guide for further reference.
The onInterceptTouchEvent() method is called whenever a touch event is detected on the surface of a ViewGroup, including on the surface of its children. If onInterceptTouchEvent() returns true, the MotionEvent is intercepted, meaning it is not passed on to the child, but rather to the onTouchEvent() method of the parent.

Related

Android find difference between two ImageView

I am developing a puzzle game like find differences on images in Android (Java).
So how can i know, where user touched on image, and is it right place where user touched.
make some CustomView extends View and override onTouchEvent method. or handle all touch events in Activity by overriding dispatchTouchEvent. you can obtain precise point of touch/action with getX() and getY() methods of MotionEvent (which is an object passed to both methods mentioned above), now its your turn to do some math and calculate which item has been touched (by default Activity is dispatching touch events to its layout e.g. inflated from XML)

Can you determine which child view was touched when handling the event in the ViewGroup?

Consider this hypothetical hierarchy...
LinearLayoutA <-- I want to handle the touches here...
|
+-SomeViewX
+-SomeOtherViewY
+-LinearLayoutB
|
+-CustomView1 <-- for these three CustomView objects
+-CustomView2
+-CustomView3
What I would like to do is know which (grand)child view was touched and handle it from within LinearLayoutA. Also, I don't control those views so I can't simply make them handle the touch internally and delegate to their parent(s).
Currently I'm manually adding touch listeners to CustomViews 1-3 but that requires a lot of 'boilerplate' work and also means I won't get notified if someone clicks on SomeViewX or SomeOtherViewY, only the specific ones I've attached the listener to.
Now in other languages such as C# with WPF, if you handle the event at the equivalent of LinearLayoutA, part of the event payload is a source, which is the view that initiated the touch, but I'm not aware of any such thing in Android.
All the examples I've seen require looping through the children and hit-testing them, then disambiguating by z-order if there's an overlap, and when you've identified the one child, then you have to go through its children and repeat.
So, is there a built-in, or 'Androidy' way to know which child in a ViewGroup was touched without manually iterating and hit-testing, or manually attaching listeners to all its children?
The OnTouchListener for ViewGroups passes in the ViewGroup as its View argument and not the child within that View that was actually touched. Since you don't have control over the source of the Views in the layout, you'll have to add the OnTouchListener manually from outside of them.
As mentioned in my comments, you can reuse the same listener for all the Views by attaching it to each of the Views you want to listen on. If you're adding these Views dynamically, it should be trivial to also call setOnTouchListener() on them as you create them.
For more on the subject, check out Android's guide to managing touch events in a ViewGroup which provides a way for the parent to intercept touch events on the child, but not vice versa.

How to detect draglike behavior without ACTION_DOWN and ACTION_UP

My problem concerns onTouch. As far as I can tell, there is no way to detect an ACTION_DOWN for one view, and than detect the ACTION_UP for another view at the same onTouch event or swipe, as every onTouch event is linked to one view.
I have a view (A) with some graphics, and on EVENT_DOWN the coordinates are detected and make a "popup" that consists of a view (B) that ownes some more views ("buttons"). B's position and size may vary form time to time. I would prefer to detect ACTION_UP on one of B's children (the "buttons").
I guess using onInterceptTouchEvent is no good. After all, B is not A's parent. Its the other way around.
Using androids drag-and-drop functionality seems a bit too much. Looks like it's intended for actually dragging graphics and transfering data. Dragging invisible graphics around to detect the finger leaving the screen is not very elegant.
Another way would be detecting B's children's positions (and size), every time the popup is shown, but that is not very smooth either.
What is the best way to detect a view A's ACTION_DOWN, and then its child B's (or it's childrens) ACTION_UP?
Or are there other ways to detect these events?
I did struggle with something very similar for a day or two, and I finally concluded that as far as I know onInterceptTouchEvent is the only way to go. I just created a container view 'C' for A and B, and then when A received an ACTION_DOWN, I instructed 'C' to intercept all further events in the swipe, test the coordinates against B's known location, and then forward the event to 'B' through a custom method if the ACTION_UP tested positive against B's bounds (be careful manually passing MotionEvents from one class to another, as the coordinates will be all wrong).
Not a very satisfying solution, but it was the only thing I could think of to do.
Also just in case you're using it, android 3.0+ has some drag/drop helper methods which I'm sure are very helpful, though I was developing for 2.x so they were useless to me.

How to get "onTouchEnd" event in Android?

What is the name of a event that is called once he user stops touching the screen for the View object?
onTouchEvent fires with a type of ACTION_UP.
You can check here to see all available events: http://developer.android.com/reference/android/view/MotionEvent.html#ACTION_UP
The one for you is ACTION_UP.
Hope this helps!
Update:
Moreover when you move outside the View without moving up your finger, ACTION_CANCEL is called. So you should handle both.

How to differentiate between sliding and clicking in android?

In pure Java there is MouseInputListener which I can use to work with those 2 events.
How do I do it with Android?
If I implement both events then only one is fired (onClickListener) and not the other.
Updated:
The question is not about detecting the finger movement.
I have a View (ImageView for example). I need to detect the click on this view which is onClickListener() and finger movement on this view (i.e. press, move then release the finger).
The problem here is that only onClickListener() is called and MotionEvent handler is not caught.
I need to be able to differentiate those 2 events as the main event should be finger movement and onClickListener() should just say "Don't click this view. Spin this view."
Hopefully this is more clear.
OnClickListener and OnTouchListener kinda obstruct each other, since they both consume the MotionEvents that get caught on the View.
Basically you can write a single OnTouchListener that checks for both things. You'll get supplied with the MotionEvent as an argument. Check it's action via MotionEvent.getAction(), e.g. if it equals MotionEvent.ACTION_DOWN (the user put the finger on the display). If the user releases the finger at approx. the same position (ACTION_UP), you may want to interpret that as a click. Otherwise interpret the positions that you get with the ACTION_MOVE event as a gesture.
But the framework already has some classes that do this interpreting work for you, check out the SimpleGestureDetector class and it's SimpleOnGestureListener. That has some callbacks for common events, e.g. onSingleTapConfirmed() and onFling(). All you need to do is supply the MotionEvents from your OnTouchListener to the GestureDetector.

Categories