web-dev-qa-db-fra.com

Vérifiez si Android WebView consomme des événements tactiles

Version courte

Comment puis-je détecter si Android WebView a consommé un événement tactile? onTouchEvent renvoie toujours true et WebViewClient's onUnhandledInputEvent n'est jamais déclenché.

Version détaillée

J'ai plusieurs WebViews dans un TwoDScrollView. Comme son nom l'indique, le TwoDScrollView peut être défilé verticalement et horizontalement. Le contenu de TwoDScrollView peut être zoomé/dézoomé. Lorsque l'utilisateur fait glisser son doigt ou utilise le pincement pour zoomer, je souhaite envoyer l'événement tactile à:

  • WebView si son contenu peut défiler/zoomer (c'est-à-dire que seul l'intérieur de WebView défilera/zoomera)
  • TwoDScrollView si la condition ci-dessus est fausse (tout le contenu de TwoDScrollView défilera/zoomera)

J'ai partiellement atteint cet objectif en utilisant les méthodes canScrollHorizontally et canScrollVertically. Mais ces méthodes ne fonctionnent que pour le "défilement natif". Cependant, dans certains cas, du JavaScript dans WebView consomme l'événement tactile, par exemple Google Maps. Dans ce cas, les méthodes retournent false. Existe-t-il un moyen de savoir si le contenu de WebView consomme les événements tactiles, c'est-à-dire qu'il est défilable/zoomable? Je ne peux pas changer le contenu du WebView, donc ma question est différente de celle-ci .

J'ai envisagé de vérifier les gestionnaires tactiles en exécutant du JavaScript dans la vue Web par la méthode evaluateJavaScript, mais selon cette réponse il n'y a pas de moyen facile d'y parvenir et la page peut aussi avoir des d'autres iframes imbriqués. Toute aide serait appréciée.

Ce que j'ai déjà essayé

  1. J'ai surchargé onTouchEvent de WebView et lu super.onTouchEvent() qui retourne toujours vrai, quoi qu'il arrive.
  2. canScrollHorizontally et canScrollVertically ne résolvent que partiellement ce problème, comme mentionné ci-dessus
  3. onScrollChanged n'est pas utile non plus
  4. WebViewClient.onUnhandledInputEvent n'est jamais déclenché
  5. J'ai envisagé d'utiliser JavaScript via evaluateJavaScript, mais c'est une solution très compliquée et laide
  6. J'ai essayé de tracer le MotionEvent par Debug.startMethodTracing. J'ai découvert qu'il se propage comme suit:
    • 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
    • Selon code source de ContentViewCore l'événement tactile se termine par une méthode native nativeOnTouchEvent et je ne sais pas ce qui se passe avec. Quoi qu'il en soit, onTouchEvent renvoie toujours true et même s'il était possible de savoir quelque part si l'événement a été consommé ou non, cela nécessiterait l'utilisation de méthodes privées qui sont également assez laides.

Remarque

Je n'ai pas besoin de savoir comment intercepter les événements tactiles envoyés à WebView, mais si la WebView les consomme, c'est-à-dire les utilise pour faire quoi que ce soit, comme le défilement, le glissement, etc.

59

Selon cela rapport de problème , pas possible. Si le code Web est sous votre contrôle, vous pouvez implémenter une interface JavaScript pour contourner ce problème. Sinon, je crains qu'il n'y ait pas de solution ici.

1
hqzxzwb

Vous pouvez transmettre tous les événements touch à GestureDetector en remplaçant onTouchEvent de WebView, afin que vous puissiez savoir when Android WebView consomme des événements tactiles n'importe où, n'importe quand en écoutant GestureDetector.

Essayez comme ceci:

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();
    }
}

J'espère que vous serez inspiré.

0
SilentKnight