Android 当滚动位置在顶部时 SwipeRefreshLayout + WebView

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24658428/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 08:33:48  来源:igfitidea点击:

SwipeRefreshLayout + WebView when scroll position is at top

androidwebviewswiperefreshlayout

提问by eugene

I'm trying to use SwipeRefreshLayout with WebView.

我正在尝试将 SwipeRefreshLayout 与 WebView 一起使用。

I'm facing the problem where in the middle of page, when user scrolls down, unwanted refresh kicks in.

我面临的问题是在页面中间,当用户向下滚动时,会出现不需要的刷新。

How do I make the refresh event only happen when webview's scroll position is at the top. (ie, he's looking at the top portion of the page)?

如何使刷新事件仅在 webview 的滚动位置位于顶部时发生。(即,他正在查看页面的顶部)?

回答by vizZ

I've managed to solve it without having to extend anything. Have a look at this snippet (Fragment-specific):

我已经设法解决它而无需扩展任何东西。看看这个片段(特定于片段的):

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

For a broader context, have a look at my answer to Android - SwipeRefreshLayout with empty textview.

对于更广泛的上下文,请查看我对Android - SwipeRefreshLayout with empty textview 的回答。

回答by hiBrianLee

I think the recommended way of doing this is to extend the SwipeRefreshLayoutand override canChildScrollUp()- https://developer.android.com/reference/android/support/v4/widget/SwipeRefreshLayout.html#canChildScrollUp()

我认为这样做的推荐方法是扩展SwipeRefreshLayout和覆盖canChildScrollUp()- https://developer.android.com/reference/android/support/v4/widget/SwipeRefreshLayout.html#canChildScrollUp()

This is how it's done in the Google IO 2014 Schedule app - https://github.com/google/iosched/blob/master/android/src/main/java/com/google/samples/apps/iosched/ui/widget/MultiSwipeRefreshLayout.java#L76

这是在 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

The CustomSwipeRefreshLayoutwill probably look like:

CustomSwipeRefreshLayout可能会是这样的:

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

And in your Activitythat has the WebView,

而在你的Activity那个有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;
    }
}

回答by Pranav

Just implement your Fragmentor Activitywith ViewTreeObserver.OnScrollChangedListenerthen set Listener like webview.getViewTreeObserver().addOnScrollChangedListener(this);

只要实现你的FragmentActivityViewTreeObserver.OnScrollChangedListener再设置监听像webview.getViewTreeObserver().addOnScrollChangedListener(this);

In onScrollChanged()method do like this

onScrollChanged()方法中这样做

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

回答by Isaac

You can solve this by extending SwipeRefreshLayout with a custom SwipeRefreshLayout that takes in the WebView and use the WebView to check the scrollY position.

您可以通过使用自定义 SwipeRefreshLayout 扩展 SwipeRefreshLayout 来解决此问题,该自定义 SwipeRefreshLayout 接受 WebView 并使用 WebView 检查 scrollY 位置。

Note: This will work for scrolling the whole page, but it may not work with nested scrolls. Also, if you have horizontal scrolling you may also want to add the logic found in this answer: https://stackoverflow.com/a/24453194

注意:这适用于滚动整个页面,但它可能不适用于嵌套滚动。此外,如果您有水平滚动,您可能还想添加在此答案中找到的逻辑: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);
    }
}

回答by Alexey

Most recent versions of support library have SwipeRefreshLayout#setOnChildScrollUpCallbackmethod which allows you to avoid subclassing SwipeRefreshLayout.

支持库的最新版本具有SwipeRefreshLayout#setOnChildScrollUpCallback允许您避免子类化的方法SwipeRefreshLayout

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

回答by Xenolion

I am answering the same question but using Kotlin. By enabling swipeRefreshLayoutwhen the scrollY of webViewgets 0:

我正在回答同样的问题,但使用 Kotlin。通过启用swipeRefreshLayout时的scrollYwebView得到0

Make this variable in your fragment or activity:

在您的片段或活动中创建此变量:

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

Then onViewCreated:

然后onViewCreated

swipeRefreshLayout.viewTreeObserver.addOnScrollChangedListener(onScrollChangedListener)

Then onStop:

然后onStop

swipeRefreshLayout.viewTreeObserver.removeOnScrollChangedListener(onScrollChangedListener)

From here everything will work well. But if the webpage your are using has a fixed header that does not scroll scrollYwill always be equal to 0. And this solution together with other solution in this page may not work.

从这里一切都会正常进行。但是,如果您使用的网页具有不滚动的固定标题,scrollY则将始终等于0. 并且此解决方案与此页面中的其他解决方案一起可能不起作用。

回答by karanatwal.github.io

I was facing Similar issue but none of the answers given here works for me. So, I got a solution from thisanswer.

我遇到了类似的问题,但这里给出的答案都不适合我。所以,我从这个答案中得到了一个解决方案。

Step 1: Create Class CustomWebView

第 1 步:创建类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);
}}

Step 2: In xmlfile use webviewlike this-

第 2 步:在xml文件中webview像这样使用-

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

Step 3: In your MainActivityuse setOnScrollChangedCallback-

第 3 步:在您的MainActivity使用中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);
            }
        }
    });
}

回答by doertsch

The answer provided by hiBrianLee almostworked for me, but as John Shelley wrote, getScrollYalways returned 0 in my case (I used a ListViewas the nested scrolling child). What worked straight away, however, was to use canScrollVerticallyinstead (which is a Viewmethod, so it's available both for ListViews and WebViews, and also for any other kind of scrolling child).

hiBrianLee 提供的答案几乎对我有用,但正如 John Shelley 所写,getScrollY在我的情况下总是返回 0(我使用 aListView作为嵌套滚动子项)。然而,直接起作用的是改为使用canScrollVertically(这是一种View方法,因此它可用于ListViews 和WebViews,也可用于任何其他类型的滚动子项)。

My layout class looks as follows:

我的布局类如下所示:

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

(As mentioned, canScrollVerticallyis a Viewmethod, so the ListViewcan be safely replaced by a general Viewor any other specialized view class.)

(如前所述,canScrollVertically是一种View方法,因此ListView可以安全地替换为通用View或任何其他专用视图类。)

回答by Akash Jp

Nothing above worked for me.Here is my approach

以上没有对我有用。这是我的方法

 @Override
 public boolean dispatchTouchEvent(MotionEvent event)
 {
super.dispatchTouchEvent(event);
int x = (int)event.getX();
int y = (int)event.getY();
 if(y>800){
     swipeRefreshLayout.setEnabled(false);
 }else {
     swipeRefreshLayout.setEnabled(true);
 }
 Log.e("yy",""+y);

switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
    case MotionEvent.ACTION_MOVE:
    case MotionEvent.ACTION_UP:
}

return false;

}

}

回答by u6517736

i find a solution for it. Just use the CoordinatorLayout as the root layout and add layout_behavior="@string/appbar_scrolling_view_behavior" to your SwipeRefreshLayout.It's perfect for me.

我找到了解决方案。只需使用 CoordinatorLayout 作为根布局并将 layout_behavior="@string/appbar_scrolling_view_behavior" 添加到您的 SwipeRefreshLayout.It 对我来说是完美的。