web-dev-qa-db-fra.com

SwipeRefreshLayout + WebView lorsque la position de défilement est en haut

J'essaie d'utiliser SwipeRefreshLayout avec WebView.

Je suis confronté au problème suivant: au milieu de la page, lorsque l'utilisateur fait défiler l'écran vers le bas, un rafraîchissement indésirable se déclenche.

Comment faire en sorte que l'actualisation ne se produise que lorsque la position de défilement de la visualisation Web est en haut. (c'est-à-dire qu'il regarde la partie supérieure de la page)?

24
eugene

J'ai réussi à le résoudre sans avoir à étendre quoi que ce soit. Jetez un coup d'œil à cet extrait (spécifique à un fragment):

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

Pour un contexte plus large, consultez ma réponse à Android - SwipeRefreshLayout avec textview vide .

22
vizZ

Je pense que la méthode recommandée consiste à étendre la SwipeRefreshLayout et à remplacer canChildScrollUp() - https://developer.Android.com/reference/Android/support/v4/widget/SwipeRefreshLayout.html#canChildScrollUp ()

Voici comment cela se fait dans l'application 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

La CustomSwipeRefreshLayout ressemblera probablement à:

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

Et dans votre Activity qui a le 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;
    }
}
19
hiBrianLee

Implémentez simplement votre Fragment ou Activity avec ViewTreeObserver.OnScrollChangedListener, puis définissez Listener comme webview.getViewTreeObserver().addOnScrollChangedListener(this);

Dans la méthode onScrollChanged() faites comme ceci

    @Override
    public void onScrollChanged() {
        if (webview.getScrollY() == 0) {
            swipeLayout.setEnabled(true);
        } else {
            swipeLayout.setEnabled(false);
        }
    }
7
Pranav

Vous pouvez résoudre ce problème en étendant SwipeRefreshLayout avec un SwipeRefreshLayout personnalisé qui intègre la vue Web et utilise cette vue pour vérifier la position de défilement.

Remarque: Cela fonctionnera pour faire défiler la page entière, mais cela peut ne pas fonctionner avec des parchemins imbriqués . De plus, si vous avez le défilement horizontal, vous pouvez également ajouter la logique trouvée dans cette réponse: https: //stackoverflow.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);
    }
}
2
Isaac

Je faisais face à un problème similaire, mais aucune des réponses données ici ne fonctionne pour moi. Donc, j'ai une solution de ceci réponse.

Étape 1: Créer une classe 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);
}}

Étape 2: Dans le fichier xml, utilisez webview comme ceci-

 <com.yourpackagename.CustomWebView
        Android:id="@+id/webview"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"/>

Étape 3: Dans votre MainActivity, utilisez 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);
            }
        }
    });
}
1

La réponse fournie par hiBrianLee presque a fonctionné pour moi, mais comme l’a écrit John Shelley, getScrollY renvoyait toujours 0 dans mon cas (j’utilisais ListView comme enfant à défilement imbriqué). Ce qui a immédiatement fonctionné, cependant, a été d'utiliser plutôt canScrollVertically (qui est une méthode View, donc disponible pour les ListViews et les WebViews, ainsi que pour tout autre type d'enfant de défilement). 

Ma classe de mise en page se présente comme suit:

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

(Comme indiqué, canScrollVertically est une méthode View. Par conséquent, la variable ListView peut être remplacée en toute sécurité par une View générale ou par toute autre classe d'affichage spécialisée.)

0
doertsch

Je réponds à la même question mais en utilisant Kotlin. En activant swipeRefreshLayout lorsque le scrollY de webView obtient 0:

Faites cette variable dans votre fragment ou activité:

private val onScrollChangedListener = ViewTreeObserver.OnScrollChangedListener{ swipeRefreshLayout.isEnabled = webView.scrollY == 0 }

Alors onViewCreated:

swipeRefreshLayout.viewTreeObserver.addOnScrollChangedListener(onScrollChangedListener)

Alors onStop:

swipeRefreshLayout.viewTreeObserver.removeOnScrollChangedListener(onScrollChangedListener)

À partir de là, tout fonctionnera bien. Mais si la page Web que vous utilisez a un en-tête fixe qui ne fait pas défiler scrollY sera toujours égal à 0 Et cette solution ainsi que d'autres solutions dans cette page peuvent ne pas fonctionner.

0
Xenolion

Les versions les plus récentes de la bibliothèque de support ont la méthode SwipeRefreshLayout#setOnChildScrollUpCallback qui vous permet d’éviter les sous-classes SwipeRefreshLayout.

mBinding.swipeRefreshLayout.setOnChildScrollUpCallback((parent, child) -> 
            mBinding.webView.getScrollY() > 10);
0
Alexey