I have to finish Activity
when user offer a right swipe anywhere in the screen. I have tried with GestureDetector
and that is works fine if there is neither ScrollView
nor RescyclerView
exists in the Activity
and in addition views that have onClickListener
also doesn't allow to detect swipe over them. So I had tried a different way by overlaying a view into the layout at the top of all them programmatically then tried to detect the swipe event over it.
private void swipeOverToExit(ViewGroup rootView) {
OverlayLayout child = new OverlayLayout(this);
ViewGroup.LayoutParams layoutParams =
new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
child.setLayoutParams(layoutParams);
rootView.addView(child);
}
OverlayLayout
public class OverlayLayout extends RelativeLayout {
private float x1, x2;
private final int MIN_DISTANCE = 150;
public OverlayLayout(Context context) {
super(context);
}
public OverlayLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public OverlayLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public OverlayLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
/*
* This method JUST determines whether we want to intercept the motion.
* If we return true, onTouchEvent will be called and we do the actual
* logic there.
*/
final int action = MotionEventCompat.getActionMasked(event);
Logger.logD("Intercept===", action + "");
// Always handle the case of the touch gesture being complete.
if (action == MotionEvent.ACTION_DOWN) {
return true; // Intercept touch event, let the parent handle swipe
}
Logger.logD("===", "Out side" + action + "");
// In general, we don't want to intercept touch events. They should be
// handled by the child view.
return false;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
x1 = event.getX();
break;
case MotionEvent.ACTION_UP:
x2 = event.getX();
float deltaX = x2 - x1;
if (Math.abs(deltaX) > MIN_DISTANCE) {
Logger.logD("Swipe Right===", MIN_DISTANCE + "");
return true;
} else {
Logger.logD("Tap===", "Tap===");
return super.onTouchEvent(event);
}
}
return true;
}
}
The logic is to intercept touch event to other view if swipe action performs over the OverlayLayout
then further end up the Activity
. However, now I can detect the swipe event on OverlayLayout
but other views couldn't respond even though I had return return super.onTouchEvent(event);
in else condition of onTouchEvent
as u can figure out there in my code. Any one please help me to make it . I'm pinned here and super excited to learn the trick :)
What you are trying to do is basically default behavior in Android Wear and its is consider as standard practices in Android Watches
to exit an app.
In Android wear DismissOverlayView does all heavy lifting for you.
Smartphones have back button while Wear rely on long press or swipe dismiss pattern for to exit screen. You should dismiss Activity on back press, mixing wear pattern in Android Smartphones will make user confused. At Least show a warning dialog to avoid accidental exit.
Solution
As I see this question is tagged with Android Activity
I would suggest you to make an Base Activity which will take care of swipe gesture and finish()
itself on left to right swipe.
The base activity class should look like this :-
public abstract class SwipeDismissBaseActivity extends AppCompatActivity {
private static final int SWIPE_MIN_DISTANCE = 120;
private static final int SWIPE_MAX_OFF_PATH = 250;
private static final int SWIPE_THRESHOLD_VELOCITY = 200;
private GestureDetector gestureDetector;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
gestureDetector = new GestureDetector(new SwipeDetector());
}
private class SwipeDetector extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
// Check movement along the Y-axis. If it exceeds SWIPE_MAX_OFF_PATH,
// then dismiss the swipe.
if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
return false;
// Swipe from left to right.
// The swipe needs to exceed a certain distance (SWIPE_MIN_DISTANCE)
// and a certain velocity (SWIPE_THRESHOLD_VELOCITY).
if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
finish();
return true;
}
return false;
}
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
// TouchEvent dispatcher.
if (gestureDetector != null) {
if (gestureDetector.onTouchEvent(ev))
// If the gestureDetector handles the event, a swipe has been
// executed and no more needs to be done.
return true;
}
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return gestureDetector.onTouchEvent(event);
}
}
Now you can make other activities extend this base Activity and they will
Inheritance
will automatically make them adopt swipe to dismiss behavior .
public class SomeActivity extends SwipeDismissBaseActivity {
Advantages of this way