Fling Gesture and Webview in Android

眉间皱痕 提交于 2019-11-27 14:06:24
techiServices

Create a GestureListener and a GestureDetector. Call the GestureDetector.onTouchEvent by overriding the webview's onTouchEvent.

You can also just override the Activity onTouchEvent btw. I can post some code if you need.

Edit: Code as requested.

public class Main extends Activity {

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        MyWebView webview = new MyWebView(this);
        setContentView(webview);
    }

    class MyWebView extends WebView {
        Context context;
        GestureDetector gd;

        public MyWebView(Context context) {
            super(context);

            this.context = context;
            gd = new GestureDetector(context, sogl);
        }

        @Override
        public boolean onTouchEvent(MotionEvent event) {
            return gd.onTouchEvent(event);
        }

        GestureDetector.SimpleOnGestureListener sogl = new GestureDetector.SimpleOnGestureListener() {
            public boolean onDown(MotionEvent event) {
                return true;
            }

            public boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY) {
                if (event1.getRawX() > event2.getRawX()) {
                    show_toast("swipe left");
                } else {
                    show_toast("swipe right");
                }
                return true;
            }
        };

        void show_toast(final String text) {
            Toast t = Toast.makeText(context, text, Toast.LENGTH_SHORT);
            t.show();
        }
    }
}

@littleFluffyKitty. I presume by default WebView touch events you mean when it brings up the zoom controls etc? I didn't test that. I have found that implementing ones own gesture detection works best (not sure if it would work best on a WebView though). You need to look at a touch event as three distinct components. The press down, the movement (if any), and the press release, as the press down, move, release always happen.

If you do a return false on the onDown the action should get passed down to the WebView touch event handler but iirc it stops the subsequent events being passed to the GestureDetector. Which is half the reason why I implement my own which is based on the Android source. iirc I got the idea from the Sony Ericsson Tutorials which is downloadable off the market. It's the 3D list which shows the code and its pretty easy to adapt.

I updated the code, this will now allow to call native events handlers if user didn't flinged

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.webkit.WebView;

public class MyWebView extends WebView {
    private boolean flinged;

    private static final int SWIPE_MIN_DISTANCE = 320;
    private static final int SWIPE_MAX_OFF_PATH = 250;
    private static final int SWIPE_THRESHOLD_VELOCITY = 200;

    public MyWebView(Context context, AttributeSet attrs) {
        super(context, attrs);
        gd = new GestureDetector(context, sogl);
    }

    GestureDetector gd;


    @Override
    public boolean onTouchEvent(MotionEvent event) {
         gd.onTouchEvent(event);
         if (flinged) {
             flinged = false;
             return true;
         } else {
             return super.onTouchEvent(event);
         }
    }

    GestureDetector.SimpleOnGestureListener sogl = new GestureDetector.SimpleOnGestureListener() {
    // your fling code here
        public boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY) {
            if (event1.getX() < 1200 && event1.getX() > 80) {
                return false;
            }
            if (Math.abs(event1.getY() - event1.getY()) > SWIPE_MAX_OFF_PATH)
                return false;
            if(event1.getX() - event2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                loadUrl("javascript:changePage('LEFT')");
                Log.i("Swiped","swipe left");
                flinged = true;
            } else if (event2.getX() - event1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                loadUrl("javascript:changePage('RIGHT')");
                Log.i("Swiped","swipe right");
                flinged = true;
            }
            return true;
        }
    };
}

@Han, forgive @techiServices his uncalled-for answer.

The problem with the code above is that in all cases it returns true for onFling and onDown. What you want instead is to return false for the events that you don't handle, or for conditions in those events that you don't handle. Or indeed, in onTouchEvent you could pass the call to the base class by returning

super.onTouchEvent(event);
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!