"Nephew" views block pinch gesture - android

I have a hierachy of custom views build as following:
Custom View A has a few View B's as children
Custom View B is like a button and needs to react to click/tap
Custom View C has a pinch gesture on it and is a sibling of A, and is under A in the view hierarchy
When pinching only on the Custom View A, everything goes well, as A does not catch any motion event and the view under it, C, receives the events and makes the pinch gesture (zoom in/out) correctly.
When tapping the Custom View B, the view is clicked and it is all good.
The issue is, when trying to pinch and one finger starts on View B, it catches its events and those are not propagated under it and no pinching ever happens on the Custom View C.
I would like to have View B react to tap only and pass all other events (pinch) to the view underneath itself, in this case Custom View C.
How can I achieve that scenario?

Found the solution!
We try to find a TapConfirmed event (using a gestureDetector to find it), and we dispatch the event directly to the sibling to pass the event:
#Override
public boolean onInterceptTouchEvent(MotionEvent event) {
if (conditionToIntercept) {
return true;
}
return false;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if(conditionToIntercept{
if (!gestureDetectorCompat.onTouchEvent(event)) {
siblingView.dispatchTouchEvent(event);
return true;
}
}
return false;
}

Related

Android: Switch touch event focus view

I am catching the touch events on an ImageView, when I touch it the view gets hidden and all the view is covered by a FrameLayout. I need that the touch events on the image view to stop and to transfer a new touch event on the new layout, which is covering this ImageView.
I have tried something like this:
imageView.setOnTouchEventListener { v, event ->
imageView.clearFocus()
frameLayout.requestFocus()
return false
}
I have tried things as dispatchEvent but it does not work in this case since the imageView is just a little part of the whole screen and the frameLayout covers all the screen.
Anyways I always end up with the same problem, where I have to lift my finger and touch the screen again so the imageView looses the old touch event and finally the framelayout starts catching it. What can I do to solve this?
you can implement touch event listener on both ImageView and FrameLayout then use a variable to know ImageView is touched or not. something like this:
boolean imageViewIsTouched = false;
imageView.setOnTouchEventListener { v, event ->
if(!imageViewIsTouched){
//do something
imageViewIsTouched = true;
}
return false
}
frameLayout.setOnTouchEventListener { v, event ->
if(imageViewIsTouched){
//do something
}
return false
}

give multitouch to view A, and A is behind to B View

I have two view A and B
A is MATCH_PARENET (width, height) and B is also MATCH_PARENT (width, height)
A view is covered by B View and B view is INVISIBLE
I have given Multitouch listener to A, but because of A is covered by B, I can not touch to A view because on top of A there is INVISIBLE, B view
Can any one help me how to do zoom-in out, rotate and move to view A
I have done by one way but it is not properly working
multiTouchListener = new MultiTouchListener();
a.setOnTouchListener(multiTouchListener);
b.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
multiTouchListener.onTouch(a, event);
return true;
}
});
I have given b's touch event to a,
but right now a is constantly moving if I simple drag my finger and stop
prevent B from getting touches, add these lines to the xml properties of B:
<View
...
android:focusable="false",
android:focusableInTouchMode="false",
android:clickable="false" />
make sure you do not add any click/touch listeners in code to B, as it'll revert those properties.

Android pass OnClick Event to underlying View in FrameLayout

Idea: I want to display an image as background. On this image, somewhere on the screen there is a little clickable View. On top of this all, a black draggabke image with a little transparent whole (displaying the underlying Views).
This is solved with a FrameLayout, whereas the image is the first frame, the View is the second frame and the ''Viewport'' is the third frame.
Now the goal is, that the user can click that second frame, if it is visible in the viewport. The problem is, that this transparency is only ''in the png'', not in the frame itself. So the solution would be to propagate the OnClick coordinates to the underlying frame. How is this possible? Is there a functionality for a FrameLayout in such cases?
Making the upper layer as clickable false, i think the click event should be ignored by it and passed to the second frame
Create a custom class that extends FrameLayout
Add the following overridden methods
#Override public boolean onTouchEvent(MotionEvent event) {
return false;
}
#Override public boolean onInterceptTouchEvent(MotionEvent event) {
return true;
}
Then add touch listener to frame layout like
framelayout.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
underLyingView.onTouchEvent(motionEvent);
return false;
}
});
This will pass onclick event to the view underLyingView which lies under FrameLayout

Touch event handling on android parent and child custom views

today I got a problem with touch event handling on android custom views.In this case i have created parent view call weekview and chiled call weekdayview.i want implement touch event like singleTap,LongPress in child view only and when i swipe on parent or child i wanna scroll parent view.when i implement touch event in both view it dose not work.
can anyone help me on this.It's really helpful to me.
Thank you
class ChildView extends View {
public void setGestureDetector (GestureDetector g)
{
gesture = g;
}
#Override
public boolean onTouchEvent (....)
{
return gesture.onTouchEvent (....); // touch event will dispatch to gesture
}
}
class ParentView extends View implements GestureDetector.OnGestureListener {
gesture = new GestureDetector (this);
child = new ChildView (...);
child.setGestureDetector (gesture);
#Override
public boolean onTouchEvent (..)
{
// handle your parent touch event here
}
public boolean onDown (...)
{
return true;
}
public boolean fling (...)
{
// here to handle child view fling
}
}
This is peso-code (not real android java) to show you the concept to use GestureDetector, you can deal with all events from your child view in your parent View. As I tested on my android phone, onTouchEvent in ChildView didn't recognize ACTION_UP very well, so even you swipe your Child View, sometimes fling will not work (it depends on ACTION_UP).
So if you want to write more accurate swipe on your Child View, better write your owen Gesture Detect class, and in your ChildView, you can do this -
float oldX;
float distanceX;
public boolean onTouchEvent (MotionEvent event...)
{
if (event.getAction == MotionEvent.ACTION_DOWN) {
// handle down
oldX = event.getX ();
}
if (event.getAction == MotionEvent.ACTION_MOVE {
// handle move
distanceX = event.getX() - oldX; // more accurate
gesture.onSwipe (distanceX); // your own gesture class
}
}
Set your swipe velocity (to detect user's intention to swipe) and override the onTouchEvent() in your child view.
Here, call super.onTouchEvent() and return, which calls your parent view. Handle the events in the parent view.

OnTouchEvent not working on child views

I have a Linear Layout that has a Button and a TextView on it. I have written a OnTouchEvent for the activity. The code works fine if I touch on the screen, but if I touch the button the code does not work. What is the possible solution for this?
public boolean onTouchEvent(MotionEvent event) {
int eventaction=event.getAction();
switch(eventaction)
{
case MotionEvent.ACTION_MOVE:
reg.setText("hey");
break;
}
return true;
}
The problem is the order of operations for how Android handles touch events. Each touch event follows the pattern of (simplified example):
Activity.dispatchTouchEvent()
ViewGroup.dispatchTouchEvent()
View.dispatchTouchEvent()
View.onTouchEvent()
ViewGroup.onTouchEvent()
Activity.onTouchEvent()
But events only follow the chain until they are consumed (meaning somebody returns true from onTouchEvent() or a listener). In the case where you just touch somewhere on the screen, nobody is interested in the event, so it flows all the way down to your code. However, in the case of a button (or other clickable View) it consumes the touch event because it is interested in it, so the flow stops at Line 4.
If you want to monitor all touches that go into your Activity, you need to override dispatchTouchEvent() since that what always gets called first, onTouchEvent() for an Activity gets called last, and only if nobody else captured the event. Be careful to not consume events here, though, or the child views will never get them and your buttons won't be clickable.
public boolean dispatchTouchEvent(MotionEvent event) {
int eventaction=event.getAction();
switch(eventaction) {
case MotionEvent.ACTION_MOVE:
reg.setText("hey");
break;
default:
break;
}
return super.dispatchTouchEvent(event);
}
Another option would be to put your touch handling code into a custom ViewGroup (like LinearLayout) and use its onInterceptTouchEvent() method to allow the parent view to steal away and handle touch events when necessary. Be careful though, as this interaction is one that cannot be undone until a new touch event begins (once you steal one event, you steal them all).
HTH
Let me add one more comment to this excellent post by #Devunwired.
If you've also set an onTouchListener on your View, then its onTouch() method will be called AFTER the dispatch methods, but BEFORE any onTouchEvent() method, i.e. in between no.3 and no.4 on #Devunwired's answer.
Try to set the descendantFocusability attribute of your layout to blocksDescendants
Activity::onTouchEvent will be called only when non of the views in the Activity WIndow consumes/handles the event. If you touch the Button, the Button will consume the events, so the Activity won't be able to handle it.
Check out following articles for more about Android Touch Event handling pipeline.
http://pierrchen.blogspot.jp/2014/03/pipeline-of-android-touch-event-handling.html
you can also try onUserInteraction():
#Override
public void onUserInteraction(){
//your code here
super.onUserInteraction();
}
works well for me!
RecyclerView list_view = findViewById(R.id.list_view);
list_view.addOnItemTouchListener(new RecyclerView.SimpleOnItemTouchListener(){
#Override
public boolean onInterceptTouchEvent(#NonNull RecyclerView rv, #NonNull MotionEvent e) {
View child = rv.findChildViewUnder(e.getX(), e.getY());
Log.i("Hello", "World");
return false;
}
});
use public boolean dispatchTouchEvent(MotionEvent event) instead on onTouchEvent()

Categories

Resources