Подтвердить что ты не робот

Убедитесь, что Android WebView потребляет сенсорные события

Краткая версия

Как я могу определить, использовал ли Android WebView событие касания? onTouchEvent всегда возвращает true и WebViewClient onUnhandledInputEvent никогда не запускается.

Подробная версия

У меня есть несколько WebView внутри TwoDScrollView. Как следует из названия, TwoDScrollView можно прокручивать как по вертикали, так и по горизонтали. Содержимое TwoDScrollView можно увеличить или уменьшить. Когда пользователь перетаскивает свой палец или использует щепотку для увеличения, я хочу отправить событие касания на:

  • WebView, если его содержимое прокручивается/масштабируется (т.е. только внутренняя часть WebView будет прокручивать/увеличивать)
  • TwoDScrollView, если указанное условие является ложным (все содержимое TwoDScrollView будет прокручиваться/масштабироваться)

Я частично добился этого, используя методы canScrollHorizontally и canScrollVertically. Но эти методы работают только для "родной прокрутки". Однако в некоторых случаях некоторый JavaScript внутри WebView потребляет сенсорное событие, например Google Maps. В этом случае методы возвращают false. Есть ли способ узнать, потребляет ли содержимое WebView события касания, то есть прокручивается/масштабируется? Я не могу изменить содержимое WebView, поэтому мой вопрос отличается от этого.

Я рассмотрел проверку обработчиков касаний, выполнив некоторый JavaScript внутри Webview с помощью метода evaluateJavaScript, но в соответствии с этим ответом нет простого способа достичь этого а также страница может иметь некоторые другие вложенные фреймы. Любая помощь будет оценена.

Что я уже пробовал

  • Я перепробовал WebView onTouchEvent и читал super.onTouchEvent(), который всегда возвращает true, независимо от того, что.
  • canScrollHorizontally и canScrollVertically только частично решают эту проблему, как указано выше.
  • onScrollChanged не полезен
  • WebViewClient.onUnhandledInputEvent никогда не запускается
  • Я рассмотрел использование JavaScript через evaluateJavaScript, но это очень сложное и уродливое решение
  • Я попытался проследить MotionEvent на Debug.startMethodTracing. Я узнал, что он распространяется следующим образом:
    • android.webkit.WebView.onTouchEvent
    • com.android.webview.chromium.WebViewChromium.onTouchEvent
    • com.android.org.chromium.android_webview.AwContents.onTouchEvent
    • com.android.org.chromium.android_webview.AwContents$AwViewMethodsImpl.onTouchEvent
    • com.android.org.chromium.content.browser.ContentViewCore.onTouchEventImpl
    • В соответствии с исходным кодом ContentViewCore событие touch заканчивается в нативном методе nativeOnTouchEvent, и я не знаю, что с ним происходит дальше, Во всяком случае, onTouchEvent всегда возвращает true, и даже если бы можно было узнать где-то, было ли это событие поглощено или нет, для этого потребуется использование частных методов, которые также довольно уродливы.

Примечание

Мне не нужно знать, как перехватывать события касания, отправляемые в WebView, но использует ли их WebView, т.е. использует их для чего-либо, например, прокрутки, перетаскивания и т.д.

4b9b3361

Ответ 1

В соответствии с этим отчет о выпуске, это невозможно. Если веб-код находится под вашим контролем, вы можете реализовать некоторый JavaScriptInterface для обхода этого. Если нет, я боюсь, что здесь нет решения.

Ответ 2

Вы можете передать все события touch в GestureDetector, переопределив onTouchEvent из WebView, чтобы вы могли знать , когда Android WebView потребляет события касания в любом месте и в любое время, слушая GestureDetector.

Попробуйте вот так:

public class MyWebView extends WebView {
    private Context context;
    private GestureDetector gestDetector;

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

        this.context = context;
        gestDetector = new GestureDetector(context, gestListener);
    }

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

    GestureDetector.SimpleOnGestureListener gestListener= 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");
            //}
            //you can trace any touch events here
            return true;
        }
    };

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

Надеюсь, ты вдохновлен.

Ответ 3

Этот код будет обрабатывать ваши прокрутки событий в веб-просмотре. Это улавливает клик и события нажатия, и сравнивает позиции каждого из них. Он не имеет в виду, что контент в веб-просмотре прокручивается, просто сравните координаты в области веб-просмотра.

public class MainActivity extends Activity implements View.OnTouchListener, Handler.Callback {

    private float x1,x2,y1,y2; //x1, y1 is the start of the event, x2, y2 is the end.
    static final int MIN_DISTANCE = 150; //min distance for a scroll event

    private static final int CLICK_ON_WEBVIEW = 1;
    private static final int CLICK_ON_URL = 2;
    private static final int UP_ON_WEBVIEW = 3;


    private final Handler handler = new Handler(this);

    public WebView webView;
    private WebViewClient client;
    private WebAppInterface webAppInt = new WebAppInterface(this);


    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        webView = (WebView)findViewById(R.id.myWebView);
        webView.setOnTouchListener(this);

        client = new WebViewClient();
        webView.setWebViewClient(client);        
        webView.loadDataWithBaseURL("file:///android_asset/", "myweb.html", "text/html", "UTF-8", "");

    }

//HERE START THE IMPORTANT PART
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (v.getId() == R.id.myWebView && event.getAction() == MotionEvent.ACTION_DOWN){
            x1 = event.getX();
            y1 = event.getY();
            handler.sendEmptyMessageDelayed(CLICK_ON_WEBVIEW, 200);
        } else if (v.getId() == R.id.myWebView && event.getAction() == MotionEvent.ACTION_UP){
            x2 = event.getX();
            y2 = event.getY();

            handler.sendEmptyMessageDelayed(UP_ON_WEBVIEW, 200);
        }

        return false;
    }

    @Override
    public boolean handleMessage(Message msg) {
        if (msg.what == CLICK_ON_URL){ //if you clic a link in the webview, thats not a scroll
            handler.removeMessages(CLICK_ON_WEBVIEW);
            handler.removeMessages(UP_ON_WEBVIEW);
            return true;
        }
        if (msg.what == CLICK_ON_WEBVIEW){
            //Handle the click in the webview
            Toast.makeText(this, "WebView clicked", Toast.LENGTH_SHORT).show();
            return true;
        }
        if (msg.what == UP_ON_WEBVIEW){
            float deltaX = x2 - x1; //horizontal move distance
            float deltaY = y2 - y1; //vertical move distance
            if ((Math.abs(deltaX) > MIN_DISTANCE) && (Math.abs(deltaX) > Math.abs(deltaY)))
            {
                // Left to Right swipe action
                if (x2 > x1)
                {
                    //Handle the left to right swipe
                    Toast.makeText(this, "Left to Right swipe", Toast.LENGTH_SHORT).show ();
                }

                // Right to left swipe action
                else
                {
                    //Handle the right to left swipe
                    Toast.makeText(this, "Right to Left swipe", Toast.LENGTH_SHORT).show ();
                }

            }
            else if ((Math.abs(deltaY) > MIN_DISTANCE) && (Math.abs(deltaY) > Math.abs(deltaX)))
            {
                // Top to Bottom swipe action
                if (y2 > y1)
                {
                    //Handle the top to bottom swipe
                    Toast.makeText(this, "Top to Bottom swipe", Toast.LENGTH_SHORT).show ();
                }

                // Bottom to top swipe action -- I HIDE MY ACTIONBAR ON SCROLLUP
                else
                {
                    getActionBar().hide();
                    Toast.makeText(this, "Bottom to Top swipe [Hide Bar]", Toast.LENGTH_SHORT).show ();
                }
            }
            return true;
        }
        return false;
    }
}

Вы также можете попытаться контролировать скорость салфетки, чтобы обнаружить ее как реальную прокрутку или прокрутку.

Я надеюсь, что это поможет вам.

Ответ 4

Попробуйте установить android:isClickable="true" в XML и создать onClickListener в коде Java.