Vérifiez si Android WebView consum 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 le WebViewClient de onUnhandledInputEvent n’est jamais déclenché.

Version détaillée

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

  • WebView si son contenu est défilable / zoomable (c.-à-d. Seul l’intérieur de WebView fera défiler / zoomer)
  • TwoDScrollView si la condition ci-dessus est fausse (tout le contenu de TwoDScrollView défilera / zoomera)

J’ai partiellement réalisé cela en utilisant les méthodes canScrollHorizontally et canScrollVertically . Mais ces méthodes ne fonctionnent que pour le “défilement natif”. Toutefois, dans certains cas, du JavaScript à l’intérieur de WebView consum l’événement tactile, par exemple Google Maps. Dans ce cas, les méthodes renvoient false. Y a-t-il un moyen de savoir si le contenu de WebView consum les événements tactiles, c.-à-d. Qu’il est défilable / zoomable? Je ne peux pas changer le contenu de WebView, ma question est donc différente de celle-ci .

J’ai envisagé de vérifier les gestionnaires tactiles en exécutant du JavaScript dans Webview par la méthode AssessJavaScript, mais selon cette réponse, il n’y a pas de moyen facile d’y parvenir et la page peut également contenir d’autres iframes nesteds. Toute aide serait appréciée.

Ce que j’ai déjà essayé

  1. J’ai annulé le onTouchEvent de WebView et lu super.onTouchEvent() qui renvoie toujours true, peu importe quoi.
  2. canScrollHorizontally et canScrollVertically ne canScrollVertically 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 moche
  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 le code source de ContentViewCore, l’événement tactile se retrouve dans une méthode native nativeOnTouchEvent et je ne sais pas ce qui se passe avec lui. Quoi qu’il en soit, onTouchEvent renvoie toujours la valeur true et même s’il était possible de savoir quelque part si l’événement était consommé ou non, il faudrait utiliser des méthodes privées qui sont également très laides.

Remarque

Je n’ai pas besoin de savoir comment intercepter les événements tactiles envoyés à WebView, mais si WebView les consum, c’est-à-dire les utiliser pour faire quelque chose, comme faire défiler, faire glisser, etc.

Selon ce rapport , 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.

Vous pouvez transmettre tous touch événements touch à GestureDetector en onTouchEvent de WebView . Vous pouvez ainsi savoir quand Android WebView consum des événements tactiles n’importe où et à tout moment 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 Ssortingng text) { Toast t = Toast.makeText(context, text, Toast.LENGTH_SHORT); t.show(); } } 

J’espère que tu seras inspiré.

Ce code gérera vos événements de défilement dans une vue Web. Ceci intercepte les événements de clic et de clic, et compare les positions de chacun. Peu importe que le contenu de la vue Web soit défilable, comparez simplement les coordonnées dans la zone de la vue Web.

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

Vous pouvez également essayer de contrôler la vitesse du balayage, pour le détecter comme un véritable balayage ou défilement.

J’espère que cela vous aide.

Essayez de définir l’ android:isClickable="true" dans le XML et créez un onClickListener dans le code Java.