In order to detect the swipe movement over the buttons or any other view , without having to implement this logic in each / em>, we must find a way to intercept this movement before them.
The ViewGroup class has the onInterceptTouchEvent () which, when implemented, allows you to intercept the MotionEvent that are sent to views daughters.
If the method returns true
, MotionEvent will be passed to the onTouchEvent()
method of ViewGroup , otherwise, it is passed to onTouchEvent()
of view where the event occurred.
We will then have to write a class that inherits from a ViewGroup (in the FrameLayout case) and implement the methods onInterceptTouchEvent()
and onTouchEvent()
to treat motion of Swipe .
public class SwipeInterceptor extends FrameLayout {
public interface OnSwipeListener{
public void onSwipeLeft();
public void onSwipeRight();
}
private OnSwipeListener mSwipeListener;
private int mTouchSlop;
private boolean mIsDragged;
private float mLastX;
private float mLastY;
private float mStartX;
private float mDeltaXTotal = 0;
public SwipeInterceptor(Context context, AttributeSet attrs) {
super(context, attrs);
setTouchSlop(context);
}
//Api level 21 ou superior
/* public SwipeInterceptor(Context context, AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
setTouchSlop(context);
}*/
public SwipeInterceptor(Context context, AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
setTouchSlop(context);
}
public SwipeInterceptor(Context context) {
super(context);
setTouchSlop(context);
}
public void setOnSwipeListenner(OnSwipeListener listener) {
mSwipeListener = listener;
}
private void setTouchSlop(Context context){
ViewConfiguration vc = ViewConfiguration.get(context);
mTouchSlop = vc.getScaledTouchSlop();
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mLastX = event.getX();
mLastY = event.getY();
mStartX = mLastX;
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
mIsDragged = false;
break;
case MotionEvent.ACTION_MOVE:
float x = event.getX();
float y = event.getY();
float xDelta = Math.abs(x - mLastX);
float yDelta = Math.abs(y - mLastY);
float xDeltaTotal = x - mStartX;
if (xDelta > yDelta && Math.abs(xDeltaTotal) > mTouchSlop) {
mIsDragged = true;
mStartX = x;
return true;
}
break;
}
return false;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
if (mIsDragged && mSwipeListener != null) {
if(mDeltaXTotal > 0)
mSwipeListener.onSwipeRight();
else mSwipeListener.onSwipeLeft();
}
mIsDragged = false;
mDeltaXTotal = 0;
break;
case MotionEvent.ACTION_MOVE:
float x = event.getX();
float y = event.getY();
float xDelta = Math.abs(x - mLastX);
float yDelta = Math.abs(y - mLastY);
mDeltaXTotal = x - mStartX;
if (!mIsDragged && xDelta > yDelta && Math.abs(mDeltaXTotal) > mTouchSlop) {
mIsDragged = true;
mStartX = x;
mDeltaXTotal = 0;
}
mLastX = x;
mLastY = y;
break;
}
return true;
}
}
As you can see, the onInterceptTouchEvent()
method only returns true
in the case of MotionEvent.ACTION_MOVE
, because that's just the movement we want to intercept.
The whole code comes down to some math to see if the move made should be considered as a Swipe and what its direction is.
The class declares the OnSwipeListener
interface with the onSwipeLeft()
and onSwipeRight()
methods that will be called when those motions are detected.
The class that implements them must be registered using the setOnSwipeListenner()
method.
Implementation
The implementation goes through, first putting your layout into our FrameLayout
<nome_da_sua_package.SwipeInterceptor xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/swipe">
<!-- coloque aqui o seu layout -->
</nome_da_sua_package.SwipeInterceptor>
and then implement the OnSwipeListener
interface.
One of the possible ways is to make your Activity implement it:
public class MainActivity extends Activity implements OnSwipeListener{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Obtém a referência ao SwipeInterceptor.
SwipeInterceptor swipe = (SwipeInterceptor)findViewById(R.id.swipe);
//Registra a nossa Activity para receber os eventos onSwipeLeft e onSwipeRight
swipe.setOnSwipeListenner(this);
}
// Declaração dos métodos da interface OnSwipeListener
@Override
public void onSwipeLeft() {
Toast.makeText(MainActivity.this, "Swipe Left", Toast.LENGTH_SHORT).show();
}
@Override
public void onSwipeRight() {
Toast.makeText(MainActivity.this, "Swipe Right", Toast.LENGTH_SHORT).show();
}
}
Inspiration: Documentation for Android and this article .