Android: ZoomPicker se rompe enTouchListener

Tengo una webview que hace uso de los controles de zoom incorporados, de la siguiente manera:

wv = new WebView(this); wv.getSettings().setBuiltInZoomControls(true); 

Nota: esto activa dos funciones principales: pinch-to-zoom e invokeZoomPicker () (este último sólo se llama cuando se realiza una acción de deslizamiento en la vista, un simple toque no lo habilita)


Y también quiero que sucedan cosas cuando ocurren eventos de contacto, usando lo siguiente

 wv.setOnTouchListener(new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { Log.i("touch", "touched!"); return false; } }); 

Cuando el WebView se carga y toco la pantalla, el registro dice "tocado" cada vez que interactúo con la pantalla, como se esperaba. Sin embargo, si hago algo que desencadenar invokeZoomPicker () (pinch to zoom no parece causar este problema, siempre y cuando el widget de zoom no aparece), onTouchListener deja de responder a mis grifos (incluso después de unos segundos , Cuando el widget desaparece de la vista).

Para asegurarse de que era invokeZoomPicker (), edité el segundo segmento de mi código de la siguiente manera:

 wv.setOnTouchListener(new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { wv.invokeZoomPicker(); Log.i("touch", "touched!"); return false; } }); 

Este nuevo método onTouch ahora sólo se activa una vez (como resultado de lo cual el zoomwidget aparece en la vista – y desaparece unos segundos más tarde), y luego el método onTouch no se vuelve a llamar hasta que la vista se vuelve a cargar – por lo que es definitivamente Un problema con el widget invokeZoomPicker () / Zoom

¿He perdido alguna parte vital del código que les permite coexistir, o simplemente tengo que elegir cuál puedo vivir sin él?

Así que después de correr en el mismo problema a mí mismo, traté de dar sentido a algunas de estas respuestas en vano. El problema es que una vez que el usuario invoca scroll (no pinch-zoom) (al menos para mí …), la instancia de WebView pierde su referencia OnTouchListener. ¿Cómo averigué esto? Bien…

Webview hereda dispatchTouchEvent () de la vista. DispatchTouchEvent llama a onTouch () (que es la función que no dispara que debe)

La razón por la que onTouch () no se llamaba era, como dije antes, que el OnTouchListener de la instancia de WebView se estaba estableciendo en null por alguna razón. Esto se puede ver poniendo un punto de interrupción en el método dispatchTouchEvent () de View

Así que para solucionar esto, extendemos WebView así:

 import android.content.Context; import android.util.AttributeSet; import android.webkit.WebView; public class TouchWebView extends WebView { WebTouchListener wtl; public TouchWebView(Context context) { super(context); } public TouchWebView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public TouchWebView(Context context, AttributeSet attrs) { super(context, attrs); } public void resetTouchListener() { if(this.wtl == null) { this.wtl = new WebTouchListener(); } this.setOnTouchListener(wtl); } @Override public boolean dispatchTouchEvent(MotionEvent event) { this.resetTouchListener(); return super.dispatchTouchEvent(event); } } 

Y luego implementamos nuestro OnTouchListener:

 import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; import android.webkit.WebView; public class WebTouchListener implements OnTouchListener { @Override public boolean onTouch(View v, MotionEvent event) { WebView.HitTestResult hr = ((TouchWebView)v).getHitTestResult(); //Log.i(TAG, "getExtra = "+ hr.getExtra() + "\t\t Type=" + hr.getType()); if (event.getAction() == MotionEvent.ACTION_DOWN) { System.out.println(hr.getExtra() + " " + hr.getType()); } // TODO Auto-generated method stub return false; } } 

OnTouch ahora disparará incluso después de hacer zoom o desplazarse

Tuve el mismo problema, pero logré resolverlo estableciendo el oyente de nuevo en mi clase extendida de WebView:

 public void invalidate() { super.invalidate(); setOnTouchListener(this); } 

Desafortunadamente, ahora tengo el problema opuesto en que los controles de zoom (el widget más / menos) ya no reciben eventos de toque. Parece que hay alguna exclusividad entre tener un OnTouchListener y el zoom, al menos en Android SDK nivel 8 (Froyo 2.2).

Esto suena como un error para mí, pero me encantaría encontrar una solución.

Tratar

 youWebView.getSettings().setBuiltInZoomControls(false); 

Es trabajo para mí.

Una solución sucia es cubrir una vista invisible en la parte superior de la vista web y detecta los toques allí, y hay que distinguir si el tacto se consume o devolver false para pasar los toques a la vista web subyacente.

La solución es bastante simple. Debe crear una clase personalizada, que amplíe una de las subclases ViewGroup como LinearLayout. A continuación, anule onInterceptTouchEvent – se llamará antes de ViewText de niño de ViewGroup. No es muy elegante poner un control webview en su subclase ViewGroup personalizada, y luego insertarlo en la jerarquía de vista de la actividad – donde se desea, pero – funciona.

 private class OwnedLayout extends LinearLayout { protected OwnedLayout(Context context, AttributeSet attrs) { super(context, attrs); } protected OwnedLayout(Context context) { super(context); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { //Put Your code here return super.onInterceptTouchEvent(ev); } } 

Este es el más cercano que podría llegar a una solución a este problema. Necesitaba fijar el foco de la entrada al WebView siempre que fue tocado. La única manera que podía hacerlo era extendiendo WebView y reemplazando la función onTouchEvent. Esta función se llama incluso después de utilizar el zoom en el WebView.

 public class NewWebView extends WebView { public NewWebView(Context context) { super(context); } public NewWebView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public NewWebView(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onTouchEvent(MotionEvent ev) { boolean consumed = super.onTouchEvent(ev); if (isClickable()) if (ev.getAction() == MotionEvent.ACTION_DOWN) { if (!hasFocus()) requestFocus(); } return consumed; } 

No olvide que si utiliza XML para crear su diseño, tendrá que cambiar "WebView" a su nombre de paquete completo.NewWebView (de lo contrario obtendrá un confuso ClassCastException si intenta hacer algo como:

  webView = (NewWebView) findViewById(R.id.new_web_view); 

Creo que hay una cierta exclusividad, por ejemplo, para una vista web 500×500 y se amplía en 1000×1000, entonces se tocó en ella, ¿ahora qué posición debe informar?

Pero realmente necesito que trabajen juntos.

Tuve un problema similar en el que onTouch no se llamó después de usar pinch para hacer zoom . Inspirado por la respuesta de jpeskin , este código funcionó para mí (añádalo en la clase que extiende WebView):

 @Override public boolean onTouchEvent(MotionEvent event) { boolean consumed = super.onTouchEvent(event); onTouch(this, event); return consumed; } 

actualizar:

 @Override public boolean onTouch(View v, MotionEvent event) { return touchListener.onTouch(v, event); } 

El touchListener es del tipo android.view.View.OnTouchListener .

Tuve el mismo problema de zoom que Stijn.V. He utilizado el código en su respuesta, pero todavía tenía un problema con el touchListener a veces se establece en null. Aquí está mi clase completa de webview, probada en Android 4.0 – 4.3

 public class BookWebView extends WebView implements OnTouchListener { private OnTouchListener mTouchListener; public BookWebView(Context context) { super(context); } public BookWebView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public BookWebView(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onTouchEvent(MotionEvent event) { boolean consumed = super.onTouchEvent(event); onTouch(this, event); return consumed; } @Override public boolean onTouch(View v, MotionEvent event) { return mTouchListener.onTouch(v, event); } @Override public void setOnTouchListener(OnTouchListener l) { super.setOnTouchListener(l); if(l != null){ mTouchListener = l; } } 

}

En aras de la integridad, aquí se explica cómo se inicializa touchEvent en mi actividad de llamada

 bookWebview.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { return mGestureDetector.onTouchEvent(event); } }); 

He encontrado el mismo problema, y ​​amplié WebView y crear mi propio ontouchlistener para evitar este error. Por ejemplo: la clase pública BookknowWebView extiende WebView {

 private GestureDetector gestureDetector; private OnTouchListener mListener; /** * @param context * @param attrs * @param defStyle */ public BookknowWebView(Context context) { super(context); } /** * @param context * @param attrs * @param defStyle */ public BookknowWebView(Context context, AttributeSet attrs) { super(context, attrs); } /** * @param context * @param attrs * @param defStyle */ public BookknowWebView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public void setBookknowOnTouchListener(OnTouchListener l){ mListener = l; } /* * @see android.webkit.WebView#onTouchEvent(android.view.MotionEvent) */ @Override public boolean onTouchEvent(MotionEvent ev) { mListener.onTouch(this, ev); return gestureDetector.onTouchEvent(ev) || super.onTouchEvent(ev); } public void setGestureDetector(GestureDetector gestureDetector) { this.gestureDetector = gestureDetector; } 

}

Funciona perfectamente bien para mí. Sólo use onTouchEvent (evento MotionEvent) en lugar de onTouch (Ver v, evento MotionEvent). Funciona incluso si setBuiltInZoomControls está establecido en true.

FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.