Reputation: 13061
i'm developing a simple android application with a RelativeLayout
and a WebView
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!!!!! :)
Upvotes: 15
Views: 26431
Reputation: 277
I have tried quite a few attempts to get this webview and swipes working. After a lot of tussle, I have written a solution that is simple and works.
I used the two following stackoverflow articles to write the code Android left/right swipe gesture in WebView activity... and Fling Gesture and Webview in Android
First set the project to an empty project, then add this first code.
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.content.Context;
import android.view.MotionEvent;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MyWebView webView = new MyWebView(this);
setContentView(webView);
//setContentView(R.layout.activity_main);
//webView = findViewById(R.id.web);
webView.setInitialScale(1);
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setLoadWithOverviewMode(true);
webView.getSettings().setUseWideViewPort(true);
webView.setScrollBarStyle(WebView.SCROLLBARS_OUTSIDE_OVERLAY);
webView.setScrollbarFadingEnabled(false);
webView.getSettings().setBuiltInZoomControls(true);
webView.getSettings().setDomStorageEnabled(true);
webView.setWebViewClient(new WebViewClient());
webView.loadUrl("http://example.com");
}
Then you want to create a custom WebView.
class MyWebView extends WebView {
Context context;
GestureDetector gd;
public MyWebView mywebview;
private static final int SWIPE_DISTANCE_THRESHOLD = 100;
private static final int SWIPE_VELOCITY_THRESHOLD = 100;
public MyWebView(Context context) {
super(context);
this.context = context;
gd = new GestureDetector(context, sogl);
mywebview = this;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
gd.onTouchEvent(event);
return super.onTouchEvent(event);
}
GestureDetector.SimpleOnGestureListener sogl = new SimpleOnGestureListener() {
public boolean onDown(MotionEvent event) {
return true;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
float distanceX = e2.getX() - e1.getX();
float distanceY = e2.getY() - e1.getY();
if (Math.abs(distanceX) > Math.abs(distanceY) && Math.abs(distanceX) > SWIPE_DISTANCE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
if (distanceX > 0) {
mywebview.goForward();
show_toast("swipe right");
}
else {
mywebview.goBack();
show_toast("swipe left");
}
return true;
}
return false;
}
};
void show_toast(final String text) {
Toast t = Toast.makeText(context, text, Toast.LENGTH_SHORT);
t.show();
}
}
@Override
public void onBackPressed() { // navigation bar
webView.goBack();
//super.onBackPressed();
}
} // END ... MainActivity extends AppCompatActivity
I have run this code in android 2020.3.1 in their emulator and on an android phone and webview and swiping left and right works. This version the onFling method can move around the page better.
Upvotes: 0
Reputation: 7581
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");
}
}
Upvotes: 2
Reputation: 15973
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.
Upvotes: 38