How to detect a swipe gesture on webview
Solution 1
Use a GestureDetector with a custom web view..
webView.setGestureDetector(new GestureDetector(new CustomeGestureDetector()));
the gesture detector:
private class CustomeGestureDetector extends SimpleOnGestureListener {
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
if(e1 == null || e2 == null) return false;
if(e1.getPointerCount() > 1 || e2.getPointerCount() > 1) return false;
else {
try { // right to left swipe .. go to next page
if(e1.getX() - e2.getX() > 100 && Math.abs(velocityX) > 800) {
//do your stuff
return true;
} //left to right swipe .. go to prev page
else if (e2.getX() - e1.getX() > 100 && Math.abs(velocityX) > 800) {
//do your stuff
return true;
} //bottom to top, go to next document
else if(e1.getY() - e2.getY() > 100 && Math.abs(velocityY) > 800
&& webView.getScrollY() >= webView.getScale() * (webView.getContentHeight() - webView.getHeight())) {
//do your stuff
return true;
} //top to bottom, go to prev document
else if (e2.getY() - e1.getY() > 100 && Math.abs(velocityY) > 800 ) {
//do your stuff
return true;
}
} catch (Exception e) { // nothing
}
return false;
}
}
}
The custom web view:
public final class CustomWebView extends WebView {
private GestureDetector gestureDetector;
/**
* @param context
* @param attrs
* @param defStyle
*/
public CustomWebView(Context context) {
super(context);
}
/**
* @param context
* @param attrs
* @param defStyle
*/
public CustomWebView(Context context, AttributeSet attrs) {
super(context, attrs);
}
/**
* @param context
* @param attrs
* @param defStyle
*/
public CustomWebView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
/*
* @see android.webkit.WebView#onScrollChanged(int, int, int, int)
*/
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
}
/*
* @see android.webkit.WebView#onTouchEvent(android.view.MotionEvent)
*/
@Override
public boolean onTouchEvent(MotionEvent ev) {
return gestureDetector.onTouchEvent(ev) || super.onTouchEvent(ev);
}
public void setGestureDetector(GestureDetector gestureDetector) {
this.gestureDetector = gestureDetector;
}
}
As said by Андрей Москвичёв:
It can be solved without deriving WebView class, by registering touch listener: webview.setOnTouchListener(new OnTouchListener() ...)
and calling gestureDetector.onTouchEvent(ev)
from it.
Solution 2
The 'webView.setGestureDetector(new GestureDetector(' solution is deprecated.
The next solution is simple to implement. Scrolling, clicking on links still works.
1 - Add this to your webView:
webView.setOnTouchListener( new OnSwipeWebviewTouchListener( getActivity(), this));
The 'this' means that you have your calling class implement the TouchListener interface methods. You can implement YOUR navigation via the methods onSwipeRight() and onSwipeLeft().
2 - Use this OnTouchListener:
public class OnSwipeWebviewTouchListener implements View.OnTouchListener {
private final GestureDetector gestureDetector;
public OnSwipeWebviewTouchListener(Context ctx, TouchListener touchListener) {
gestureDetector = new GestureDetector(ctx, new GestureListener(touchListener));
}
@Override
public boolean onTouch(View v, MotionEvent event) {
return gestureDetector.onTouchEvent(event);
}
private final class GestureListener extends GestureDetector.SimpleOnGestureListener {
private TouchListener touchListener;
GestureListener(TouchListener touchListener) {
super();
this.touchListener = touchListener;
}
@Override
public boolean onDown(MotionEvent e) {
return false; // THIS does the trick
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
boolean result = false;
try {
float diffY = e2.getY() - e1.getY();
float diffX = e2.getX() - e1.getX();
if (Math.abs(diffX) > Math.abs(diffY)) {
// You can customize these settings, so 30 is an example
if (Math.abs(diffX) > 30 && Math.abs(velocityX) > 30) {
if (diffX > 0) {
touchListener.onSwipeRight();
} else {
touchListener.onSwipeLeft();
}
result = true;
}
} else {
result = false;
}
} catch (Exception exception) {
exception.printStackTrace();
}
return result;
}
}
}
3 - An example of the TouchListner could be:
public interface TouchListener {
default void onSwipeLeft() {
Logger.d( "Swipe left");
}
default void onSwipeRight() {
Logger.d( "Swipe right");
}
}
Jayyrus
I'm an Italian Software Engineer. I like very much to learn and study new technologies
Updated on August 28, 2021Comments
-
Jayyrus almost 3 years
i'm developing a simple android application with a
RelativeLayout
and aWebView
inside.I have to detect swipe from bottom to top done only in the 20% of the left part of the screen. So when user swipe in that space from bottom to top i have to show a custom dialog.
What i try is:
import android.app.Activity; import android.view.MotionEvent; import android.view.View; public class ActivitySwipeDetector implements View.OnTouchListener { static final String logTag = "ActivitySwipeDetector"; private Activity activity; static final int MIN_DISTANCE = 100; private float downY, upY; public ActivitySwipeDetector(Activity activity){ this.activity = activity; } public void onRightToLeftSwipe(){ } public void onLeftToRightSwipe(){ } public void onTopToBottomSwipe(){ } public void onBottomToTopSwipe(){ System.out.println("BOTTOM TO TOP SWIPE DONE!"); } public boolean onTouch(View v, MotionEvent event) { switch(event.getAction()){ case MotionEvent.ACTION_DOWN: { downY = event.getY(); return true; } case MotionEvent.ACTION_UP: { upY = event.getY(); float deltaY = downY - upY; if(Math.abs(deltaY) > MIN_DISTANCE){ if(deltaY > 0) { this.onBottomToTopSwipe(); return true; } } else { return false; } return true; } } return false; } } layout = (RelativeLayout)this.findViewById(R.id.layout); layout.setOnTouchListener(activitySwipeDetector);
But it doesn't do nothing!
So i try creating a custom webview in this way:
import android.content.Context; import android.util.AttributeSet; import android.view.MotionEvent; import android.webkit.WebView; public class MyWebView extends WebView { public MyWebView(Context context) { super(context); } public MyWebView(Context context,AttributeSet set){ super(context,set); } @Override public boolean onTouchEvent(MotionEvent evt) { boolean consumed = super.onTouchEvent(evt); if (isClickable()) { switch (evt.getAction()) { case MotionEvent.ACTION_DOWN: lastTouchY = evt.getY(); downTime = evt.getEventTime(); hasMoved = false; break; case MotionEvent.ACTION_MOVE: hasMoved = moved(evt); break; case MotionEvent.ACTION_UP: float actualTouchY = evt.getY(); long currentTime = evt.getEventTime(); float difference = Math.abs(lastTouchY - actualTouchY); long time = currentTime - downTime; if ( (lastTouchY < actualTouchY) && (time < 220) && (difference > 100) ) { System.out.println("SWIPE1"); } if ( (lastTouchY > actualTouchY) && (time < 220) && (difference > 100) ) { System.out.println("SWIPE2"); } break; } } return consumed || isClickable(); } long downTime; private float lastTouchY; private boolean hasMoved = false; private boolean moved(MotionEvent evt) { return hasMoved || Math.abs(evt.getY() - lastTouchY) > 10.0; } }
but with no success!!! can someone help me?? THAnks!!!!! :)
-
Jayyrus almost 12 yearsgreat!!!! i remove all except the if of bottom to top ( what i need ) and i see that if i leave webView.getScrollY() >= webView.getScale() * (webView.getContentHeight() - webView.getHeight() it give me exception. but it works great!!!!!!! can i tell me how to recognize that gesture only on a part of screen ? thanks!
-
Nermeen almost 12 yearssomething like if(e1.getX() > yourLimit || e2.getX() > yourLimit) return false; (//do not handle)
-
Андрей Москвичёв about 10 yearsThanks for information. It can be solved without deriving WebView class, by registering touch listener: webview.setOnTouchListener(new OnTouchListener() ...) and calling gestureDetector.onTouchEvent(ev) from it.
-
Prabhakaran almost 9 yearsHi how to add pinch zoom in this. its not working now.
-
Gowthaman M about 7 years@Nermeen how to implement inside activity can you help with complete code?
-
macno almost 7 yearsThe constructor
new GestureDetector(new CustomeGestureDetector()));
has been deprecated, just replace it with:new GestureDetector(mContext, new CustomeGestureDetector()));
where mContext is the current Context