Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Need ability to consume touch events #27

Closed
xpathexception opened this issue Jan 26, 2018 · 4 comments
Closed

Need ability to consume touch events #27

xpathexception opened this issue Jan 26, 2018 · 4 comments

Comments

@xpathexception
Copy link
Contributor

In this sample I attached click counter to root view and an edit text to show clicks. The problem is that any underlying view will process any swipe action as click after ACTION_UP. I would like to have an ability to consume touch events if swipe action was correctly handled in callback.

Default behavior (now):
no-consuming

Requested behavior:
consuing

@pwittchen
Copy link
Owner

Hi,

Thanks for reporting the issue. Can you share some code?

Regards.

@xpathexception
Copy link
Contributor Author

xpathexception commented Jan 26, 2018

In my opinion the "proper" way to do so is to make SwipeListener return boolean value which indicates our needs in event consumption. As far as by default there were no consumption, we can return false by default:

public interface SwipeListener{
	boolean onSwipedLeft(final MotionEvent event);

	boolean onSwipedRight(final MotionEvent event);

	boolean onSwipedUp(final MotionEvent event);

	boolean onSwipedDown(final MotionEvent event);

	//...
}

public abstract class SimpleSwipeListener implements SwipeListener{
	@Override
	public boolean onSwipedLeft(MotionEvent event){
		return false;
	}

	@Override
	public boolean onSwipedRight(MotionEvent event){
		return false;
	}

	@Override
	public boolean onSwipedUp(MotionEvent event){
		return false;
	}

	@Override
	public boolean onSwipedDown(MotionEvent event){
		return false;
	}

	//...
}

Next we need to change Swipe#dispatchTouchEvent and Swipe#onActionUp methods to allow them pass by values returned by SwipeListener:

public class Swipe{
	//...

	public boolean dispatchTouchEvent(final MotionEvent event){
		checkNotNull(event, "event == null");
		boolean isEventConsumed = false;

		switch (event.getAction()) {
			case MotionEvent.ACTION_DOWN:
				onActionDown(event);
				break;
			case MotionEvent.ACTION_UP:
				isEventConsumed = onActionUp(event);
				break;
			case MotionEvent.ACTION_MOVE:
				onActionMove(event);
				break;
			default:
				break;
		}

		return isEventConsumed;
	}

	private boolean onActionUp(final MotionEvent event){
		boolean isEventConsumed = false;

		if (swipedHorizontally) {
			if (swipedRight) {
				isEventConsumed |= swipeListener.onSwipedRight(event);
			}
		}

		if (swipedVertically) {
			//...
		}

		return isEventConsumed;
	}

	//...
}

So now we can use modified SwipeListener and Swipe#dispatchTouchEvent in our activity like that:

public class MyActivity extends Activity{
	private Swipe swipe;

	@Override
	public void onCreate(Bundle savedInstanceState, PersistableBundle persistentState){
		super.onCreate(savedInstanceState, persistentState);

		swipe = Swipe();
	    swipe.setListener(new SimpleSwipeListener(){
		    @Override
		    public boolean onSwipedRight(MotionEvent event){
				return foo();
		    }
	    });
	}

	private boolean foo(){
		//TODO: Decide here to consume event or not
	}

	@Override
	public boolean dispatchTouchEvent(MotionEvent ev){
		return swipe.dispatchTouchEvent(ev) || super.dispatchTouchEvent(ev);
	}
}

I don't really know if there any need to consume ACTION_DOWN or ACTION_MOVE events but modifying only ACTION_UP gives me expected result.

For demonstrating library's behavior I changed activity_main.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
				xmlns:tools="http://schemas.android.com/tools"
				android:id="@+id/root_layout"
				android:layout_width="match_parent"
				android:layout_height="match_parent"
				android:gravity="center"
				android:paddingBottom="@dimen/activity_vertical_margin"
				android:paddingLeft="@dimen/activity_horizontal_margin"
				android:paddingRight="@dimen/activity_horizontal_margin"
				android:paddingTop="@dimen/activity_vertical_margin">
	
	<TextView android:id="@+id/info"
			  android:layout_width="wrap_content"
			  android:layout_height="wrap_content"
			  android:text="@string/hello_swipe_detector"
			  android:textSize="@dimen/activity_text_size"/>
	
	<TextView android:id="@+id/txt_root_touched"
			  android:layout_width="wrap_content"
			  android:layout_height="wrap_content"
			  
			  android:layout_alignParentBottom="true"
			  android:text="Root layout was not touched"/>

</RelativeLayout> 

Also I added touchCounter property and created listener in SwipeActivity#onCreate:

root_layout.setOnClickListener {
	touchCounter ++
	if (touchCounter > 0) txt_root_touched.text = "Root touched $touchCounter time(s)"
}

@pwittchen
Copy link
Owner

pwittchen commented Jan 26, 2018

Thanks for a detailed post.

I'm not really sure if returning a boolean in listener is the right way to go. E.g. View.OnClickListener in Android SDK doesn't return anything. A method inside the interface of the listener should just listen to events - not return any values. Nevertheless, I've seen that ViewGroup.dispatchTouchEvent returns boolean, so we can consider such change and maybe it's a good idea for listeners regarding touch events.

As you already figured out the potential solution, Pull Request is welcome and may speed up the process of library update (please, don't forget about unit tests). :-)

Regards,
Piotr

@pwittchen
Copy link
Owner

Done in #28.

@pwittchen pwittchen mentioned this issue Jan 30, 2018
7 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants