Eventos de desplazamiento de HTML en un WebView de Android que está dentro de un ScrollView

Tengo una página web para fines de prueba ( https://storage.googleapis.com/htmltestingbucket/nested_scroll_helper.html ) que sólo imprime un contador del evento de desplazamiento que el html ha capturado en un encabezado fijo

Cuando el WebView de Android es el único elemento desplazable en el fragmento, todo está bien y WebView envía los eventos de desplazamiento a la página

Si quiero añadir elementos nativos por encima y por debajo del WebView, las cosas se vuelven mucho más complejas.

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:custom="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="20dp" android:text="SOMETHING ABOVE THE WEBVIEW" /> <WebView android:id="@+id/webview" android:layout_width="match_parent" android:layout_height="match_parent" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="20dp" android:text="SOMETHING BELOW THE WEBVIEW" /> </LinearLayout> </ScrollView> 

Sé que no es bueno tener un WebView dentro de un ScrollView, pero tengo que proporcionar una sola experiencia de desplazamiento con contenido híbrido y eventos de desplazamiento adecuados en el documento html. He encontrado un montón de preguntas sobre el tema, pero pude crear una solución completa de extremo a extremo


Además, sé que pelusa tiene un cheque oficial para eso:

NestedScrolling ————— Resumen: Widgets de desplazamiento anidados

Prioridad: 7/10 Gravedad: Advertencia Categoría: Corrección

Un widget de desplazamiento, como un ScrollView, no debe contener widgets de desplazamiento anidados, ya que esto tiene varios problemas de usabilidad

Y, sin embargo, no puedo implementar el contenido de la vista web en nativo así que necesito una manera alternativa de hacer eso

Para mantener la vista Web dentro de scrollview aquí, necesita medir la altura de la vista web y establecerla en parámetros de diseño.

Aquí he tratado de dar respuesta a la vista web desplazable.

 <ScrollView android:layout_width="fill_parent" android:background="#FF744931" android:layout_height="fill_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" tools:ignore="WebViewLayout"> <TextView android:id="@+id/txtVoiceSeachQuery" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#FF0000" android:textSize="26sp" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="20dp" android:text="SOMETHING ABOVE THE WEBVIEW" /> <com.example.ScrollableWebView android:id="@+id/webview" android:layout_width="match_parent" android:layout_height="match_parent" app:isWebViewInsideScroll="true" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="20dp" android:text="SOMETHING BELOW THE WEBVIEW" /> </LinearLayout> </ScrollView> 

Res / values ​​/ attrs.xml

Para agregar un atributo para el control personalizado

 <?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="ScrollableWebView"> <attr name="isWebViewInsideScroll" format="boolean"></attr> </declare-styleable> </resources> 

ScrollableWebView

 public class ScrollableWebView extends WebView { private boolean webViewInsideScroll = true; public static final String RESOURCE_NAMESPACE = "http://schemas.android.com/apk/res-auto"; public ScrollableWebView(Context context) { super(context); } public ScrollableWebView(Context context, AttributeSet attrs) { super(context, attrs); setWebViewInsideScroll(attrs.getAttributeBooleanValue (RESOURCE_NAMESPACE, "isWebViewInsideScroll", true)); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (isWebViewInsideScroll()) { int expandSpec = MeasureSpec.makeMeasureSpec(MEASURED_SIZE_MASK, MeasureSpec.AT_MOST); super.onMeasure(widthMeasureSpec, expandSpec); ViewGroup.LayoutParams params = getLayoutParams(); params.height = getMeasuredHeight(); setLayoutParams(params); } else { super.onMeasure(widthMeasureSpec, heightMeasureSpec); } } public boolean isWebViewInsideScroll() { return webViewInsideScroll; } public void setWebViewInsideScroll(boolean webViewInsideScroll) { this.webViewInsideScroll = webViewInsideScroll; } } 

Para obtener el valor del atributo también puede utilizar Stylable pero aquí he hecho sin usarlo.

 ScrollableWebView webview = (ScrollableWebView) findViewById(R.id.webview); webview.loadUrl("https://storage.googleapis.com/htmltestingbucket/nested_scroll_helper.html"); 

A continuación se muestra el enlace de salida

  • Muestra la vista de texto (cualquier vista) en la parte superior dentro de scrollview con webview
  • Mostrar TextView (cualquier vista) en la parte inferior dentro de scrollview con webview

Si no quieres crear archivo de atributos y agregar atributos personalizados en res / values ​​/ attrs.xml, puedes ignorar ese archivo y comprobar este pastebin aquí que he dado sin ningún atributo personalizado como isWebViewInsideScroll . Usted puede quitarlo de la disposición del xml también. Déjame saber si algo.

Si coloca webview dentro de scrollview no obtendrá efecto de desplazamiento html, porque su contenido de webview no se desplazará (se colocará lengtth completo dentro de scrollview.)
Para hacer frente a su necesidad de colocar elementos por encima y por debajo puede escuchar webview desplazarse y utilizar DragViewHelper o nineoldandroids para mover el header y el footer , por lo que el usuario piensa, son elemento único (no necesita scrollview).

 webView.setOnScrollChangeListener(new View.OnScrollChangeListener() { @Override public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) { ViewHelper.setTranslationY(headerTextView, -event.getY()); } }); public class ObservableWebView extends WebView { private OnScrollChangeListener onScrollChangeListener; public ObservableWebView(Context context) { super(context); } public ObservableWebView(Context context, AttributeSet attrs) { super(context, attrs); } public ObservableWebView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { super.onScrollChanged(l, t, oldl, oldt); if (onScrollChangeListener != null) { onScrollChangeListener.onScrollChange(this, l, t, oldl, oldt); } } public void setOnScrollChangeListener(OnScrollChangeListener onScrollChangeListener) { this.onScrollChangeListener = onScrollChangeListener; } public OnScrollChangeListener getOnScrollChangeListener() { return onScrollChangeListener; } public interface OnScrollChangeListener { /** * Called when the scroll position of a view changes. * * @param v The view whose scroll position has changed. * @param scrollX Current horizontal scroll origin. * @param scrollY Current vertical scroll origin. * @param oldScrollX Previous horizontal scroll origin. * @param oldScrollY Previous vertical scroll origin. */ void onScrollChange(WebView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY); } } 

Este ejemplo debe ayudarle a ocultar el header , nineoldandroid utilizado nineoldandroid para ello

De hecho no es tan bueno poner una vista desplazable en otro. Trate de usar esto:

 <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> 

Y

 <WebView android:id="@+id/webview" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1"/> 

Parece que la forma más elegante que podría encontrar para manejar esto es como sigue: – Escuchar los rollos de SrollView: Puede utilizar un ObservableScrollView o llamar a setOnScrollChangeListener () desde el nivel 23 de la API – Calcular la desplazamiento Y en píxeles – Llamar a WebView. AssessmentJavascript () – Pasar todos los detalles del evento scroll Entonces los conceptos generales pasan: "$ (document) .trigger ('scroll'); Como el primer param evaluarJavascript

Todavía estoy probando los detalles y el trabajo de las torceduras, pero parece que la mejor manera de ir, voy a tratar de editar esta respuesta con más información como yo resolver esto

Si de todos modos tiene una mejor solución para me gustaría oírlo

Tengo el mismo problema recientemente y encontré tus publicaciones aquí 🙂

Tengo un WebView anidado en un ScrollVIew . Y la página que WebView en WebView necesita llamar a una función JS cuando se desplaza hasta el final, pero en la vista de desplazamiento, window.onscroll = functionXXX() {} página web nunca se llama.

Finalmente, tengo que fijar un OnScrollListener al ScrollView , y llamar mi función de JS manualmente por el código abajo

 @Override public void onScroll(int scrollY) { if (!scrollView.canScrollVertically(scrollY)) { mWebView.loadUrl("javascript:functionXXX();"); } } 

Tal vez nuestras situaciones son diferentes, pero espero que te dé una inspiración 🙂

  • ¿Cómo generar enlace waze meetup con fallback web?
  • Cómo mostrar el contenido web en iOS y Android mediante QML
  • Android Fragmento WebView
  • WebView deshacerse de doble toque zoom.
  • Guardar el estado de WebView y restaurar en ANDROID
  • Cómo acceder a mi 127.0.0.1:8000 desde Android tablet
  • Problema con el zoom de texto de WebView en Android
  • Cómo mostrar texto marathi en Android procedente de webservice
  • Ampliar / reducir en webview android
  • Aumentar el tamaño de la cuota WebSQL en un WebView
  • Que puede reemplazar la función capturePicture
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.