android - SwipeRefreshLayout+WebView cuando la posición de desplazamiento está en la parte superior
(11)
Estoy tratando de usar SwipeRefreshLayout con WebView.
Estoy enfrentando el problema donde, en medio de la página, cuando el usuario se desplaza hacia abajo, entra en acción una actualización no deseada
¿Cómo puedo hacer que el evento de actualización solo ocurra cuando la posición de desplazamiento de webview está en la parte superior? (es decir, está mirando la parte superior de la página)?
Creo que la forma recomendada de hacer esto es extender SwipeRefreshLayout
y anular canChildScrollUp()
- https://developer.android.com/reference/android/support/v4/widget/SwipeRefreshLayout.html#canChildScrollUp()
Así es como se hace en la aplicación Google IO 2014 Schedule: https://github.com/google/iosched/blob/master/android/src/main/java/com/google/samples/apps/iosched/ui/widget/MultiSwipeRefreshLayout.java#L76
El CustomSwipeRefreshLayout
probablemente se verá como:
public class CustomSwipeRefreshLayout extends SwipeRefreshLayout {
private CanChildScrollUpCallback mCanChildScrollUpCallback;
public interface CanChildScrollUpCallback {
boolean canSwipeRefreshChildScrollUp();
}
public void setCanChildScrollUpCallback(CanChildScrollUpCallback canChildScrollUpCallback) {
mCanChildScrollUpCallback = canChildScrollUpCallback;
}
@Override
public boolean canChildScrollUp() {
if (mCanChildScrollUpCallback != null) {
return mCanChildScrollUpCallback.canSwipeRefreshChildScrollUp();
}
return super.canChildScrollUp();
}
}
Y en tu Activity
que tiene el WebView
,
public class FooActivity
implements CustomSwipeRefreshLayout.CanChildScrollUpCallback {
private CustomSwipeRefreshLayout mRefreshLayout;
private WebView mWebView;
@Override
protected void onCreate(Bundle savedInstanceState) {
// after initialization
mRefreshLayout.setCanChildScrollUpCallback(this);
}
@Override
public boolean canSwipeRefreshChildScrollUp() {
return mWebview.getScrollY() > 0;
}
}
Descubrí que el problema estaba deshabilitado en la vista web (no en SwipeRefreshLayout). No será posible hacer esto en todas las situaciones, pero fue en la mía.
webView.setNestedScrollingEnabled(false);
Encuentro una solución para ello. Simplemente use CoordinatorLayout como diseño raíz y agregue layout_behavior = "@ string / appbar_scrolling_view_behavior" a su SwipeRefreshLayout. Es perfecto para mí.
Estoy respondiendo la misma pregunta pero usando Kotlin. Al habilitar swipeRefreshLayout
cuando el scrollY de webView
obtiene 0
:
Haz esta variable en tu fragmento o actividad:
private val onScrollChangedListener = ViewTreeObserver.OnScrollChangedListener{ swipeRefreshLayout.isEnabled = webView.scrollY == 0 }
Entonces onViewCreated
:
swipeRefreshLayout.viewTreeObserver.addOnScrollChangedListener(onScrollChangedListener)
Entonces onStop
:
swipeRefreshLayout.viewTreeObserver.removeOnScrollChangedListener(onScrollChangedListener)
Desde aquí todo funcionará bien. Pero si la página web que está utilizando tiene un encabezado fijo que no se desplaza, scrollY
siempre será igual a 0
. Y esta solución junto con otra solución en esta página puede no funcionar.
He logrado resolverlo sin tener que extender nada. Echa un vistazo a este fragmento (específico del fragmento):
private ViewTreeObserver.OnScrollChangedListener mOnScrollChangedListener;
@Override
public void onStart() {
super.onStart();
swipeLayout.getViewTreeObserver().addOnScrollChangedListener(mOnScrollChangedListener =
new ViewTreeObserver.OnScrollChangedListener() {
@Override
public void onScrollChanged() {
if (mWebView.getScrollY() == 0)
swipeLayout.setEnabled(true);
else
swipeLayout.setEnabled(false);
}
});
}
@Override
public void onStop() {
swipeLayout.getViewTreeObserver().removeOnScrollChangedListener(mOnScrollChangedListener);
super.onStop();
}
Para un contexto más amplio, eche un vistazo a mi respuesta a Android - SwipeRefreshLayout con vista de texto vacía .
La respuesta proporcionada por hiBrianLee casi me funcionó, pero como escribió John Shelley, getScrollY
siempre devolvió 0 en mi caso (usé un ListView
como el niño de desplazamiento anidado). Sin embargo, lo que funcionó de inmediato fue utilizar canScrollVertically
(que es un método de View
, por lo que está disponible tanto para ListView
s como para WebView
s, y también para cualquier otro tipo de niño con desplazamiento).
Mi clase de diseño se ve como sigue:
public class NestedScrollSwipeLayout extends SwipeRefreshLayout {
private ListView scrollChild;
public NestedScrollSwipeLayout(Context context) {
super(context);
}
public NestedScrollSwipeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setScrollChild(ListView child) {
this.scrollChild = child;
}
@Override
public boolean canChildScrollUp() {
return (scrollChild != null && scrollChild.canScrollVertically(-1)) ||
super.canChildScrollUp();
}
}
(Como se mencionó, canScrollVertically
es un método de View
, por lo que ListView
puede ser reemplazado de forma segura por una View
general o cualquier otra clase de vista especializada).
Las versiones más recientes de la biblioteca de soporte tienen SwipeRefreshLayout#setOnChildScrollUpCallback
método SwipeRefreshLayout#setOnChildScrollUpCallback
que le permite evitar la subclasificación de SwipeRefreshLayout
.
mBinding.swipeRefreshLayout.setOnChildScrollUpCallback((parent, child) ->
mBinding.webView.getScrollY() > 10);
Me enfrentaba a un problema similar, pero ninguna de las respuestas dadas aquí funciona para mí Entonces, tengo una solución de this respuesta.
Paso 1 : Crear clase CustomWebView
public class CustomWebView extends WebView{
private OnScrollChangedCallback mOnScrollChangedCallback;
public CustomWebView(final Context context)
{
super(context);
}
public CustomWebView(final Context context, final AttributeSet attrs)
{
super(context, attrs);
}
public CustomWebView(final Context context, final AttributeSet attrs, final int defStyle)
{
super(context, attrs, defStyle);
}
@Override
protected void onScrollChanged(final int l, final int t, final int oldl, final int oldt)
{
super.onScrollChanged(l, t, oldl, oldt);
if(mOnScrollChangedCallback != null) mOnScrollChangedCallback.onScroll(l, t);
}
public OnScrollChangedCallback getOnScrollChangedCallback()
{
return mOnScrollChangedCallback;
}
public void setOnScrollChangedCallback(final OnScrollChangedCallback onScrollChangedCallback)
{
mOnScrollChangedCallback = onScrollChangedCallback;
}
/**
* Impliment in the activity/fragment/view that you want to listen to the webview
*/
public static interface OnScrollChangedCallback
{
public void onScroll(int horizontal, int vertical);
}}
Paso 2 : en el archivo xml use webview
como este-
<com.yourpackagename.CustomWebView
android:id="@+id/webview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
Paso 3 : en su MainActivity
use setOnScrollChangedCallback
-
mWebView.setOnScrollChangedCallback(new CustomWebView.OnScrollChangedCallback(){
public void onScroll(int horizontal, int vertical){
System.out.println("=="+horizontal+"---"+vertical);
//this is to check webview scroll behaviour
if (vertical<50){
swipeRefreshLayout.setEnabled(true);
}else{
swipeRefreshLayout.setEnabled(false);
}
}
});
}
Puede resolver esto extendiendo SwipeRefreshLayout con un SwipeRefreshLayout personalizado que toma el WebView y use el WebView para verificar la posición de desplazamiento.
Nota: Esto funcionará para desplazar toda la página, pero puede que no funcione con los desplazamientos anidados. Además, si tiene desplazamiento horizontal, es posible que también desee agregar la lógica que se encuentra en esta respuesta: https://.com/a/24453194
public class CustomSwipeToRefresh extends SwipeRefreshLayout {
private final int yScrollBuffer = 5;
private WebView mWebView;
public CustomSwipeToRefresh(Context context, WebView webView) {
super(context);
mWebView = webView;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
if (mWebView.getScrollY() > yScrollBuffer)
return false;
return super.onInterceptTouchEvent(event);
}
}
Simplemente implemente su Fragment
o Activity
con ViewTreeObserver.OnScrollChangedListener
luego configure el Oyente como webview.getViewTreeObserver().addOnScrollChangedListener(this);
En el método onScrollChanged()
haz esto
@Override
public void onScrollChanged() {
if (webview.getScrollY() == 0) {
swipeLayout.setEnabled(true);
} else {
swipeLayout.setEnabled(false);
}
}
Use SwipeRefreshLayout normalmente como lo hace con otras vistas, pero habilite el desplazamiento anidado.
swipeRefreshLayout.setNestedScrollingEnabled(true);