滚动位置位于顶部时,SwipeRefreshLayout + WebView

时间:2014-07-09 15:56:18

标签: android webview swiperefreshlayout

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

我遇到的问题是在页面中间,当用户向下滚动时,不必要的刷新就会开始。

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

15 个答案:

答案 0 :(得分:26)

我设法解决它而不必扩展任何东西。看一下这个片段(片段特定的):

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

有关更广泛的背景,请查看我对Android - SwipeRefreshLayout with empty textview的回答。

答案 1 :(得分:20)

我认为推荐的方法是延长SwipeRefreshLayout并覆盖canChildScrollUp() - https://developer.android.com/reference/android/support/v4/widget/SwipeRefreshLayout.html#canChildScrollUp()

这就是在Google IO 2014计划应用中完成的工作 - https://github.com/google/iosched/blob/master/android/src/main/java/com/google/samples/apps/iosched/ui/widget/MultiSwipeRefreshLayout.java#L76

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

ActivityWebView

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

答案 2 :(得分:7)

只需使用Fragment实施您的ActivityViewTreeObserver.OnScrollChangedListener,然后将听众设置为webview.getViewTreeObserver().addOnScrollChangedListener(this);

onScrollChanged()方法中,这样做

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

答案 3 :(得分:2)

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

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

答案 4 :(得分:1)

我面临着类似的问题,但这里给出的答案都不适用于我。所以,我从this回答得到了一个解决方案。

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

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

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

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

答案 5 :(得分:1)

我正在回答相同的问题,但使用的是Kotlin。通过在webView的scrollY得到0时启用private val onScrollChangedListener = ViewTreeObserver.OnScrollChangedListener{ swipeRefreshLayout.isEnabled = webView.scrollY == 0 }

在您的片段或活动中添加此变量:

onViewCreated

然后swipeRefreshLayout.viewTreeObserver.addOnScrollChangedListener(onScrollChangedListener)

onStop

然后swipeRefreshLayout.viewTreeObserver.removeOnScrollChangedListener(onScrollChangedListener)

scrollY

从这里开始一切都会很好。但是,如果您正在使用的网页具有固定的标题且不会滚动0,则该标题将始终等于< InputFile sed -e '/Header_one/i Header_one' -e '/Header_one/,/s/d' > outputFile。并且此解决方案与本页面中的其他解决方案可能不起作用。

答案 6 :(得分:1)

你可以试试这个:

适用于 API >= 23 Android Marshmallow

webView.setOnScrollChangeListener(new View.OnScrollChangeListener() {
        @Override
        public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
            swipeRefreshLayout.setEnabled(scrollY == 0);
        }
    });

编辑 1: 如果网页具有嵌套滚动内容,这将不起作用。因此,我决定使用简单的 ImageButton 来重新加载网页,而不是使用 SwipeRefreshLayout。

答案 7 :(得分:0)

hiBrianLee提供的答案几乎为我工作,但正如John Shelley所写,getScrollY总是在我的情况下返回0(我使用ListView作为嵌套滚动儿童)。然而,直接使用的是使用canScrollVertically代替View方法,因此它适用于ListViewWebView s,也适用于任何其他类型的滚动孩子)。

我的布局类如下所示:

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

(如上所述,canScrollVerticallyView方法,因此ListView可以安全地替换为通用View或任何其他专门的视图类。)

答案 8 :(得分:0)

最新版本的支持库都具有SwipeRefreshLayout#setOnChildScrollUpCallback方法,该方法可避免子类化SwipeRefreshLayout

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

答案 9 :(得分:0)

以上都不适合我。这是我的方法

free(ptr)

}

答案 10 :(得分:0)

// swipe - active only when WebView Y==0        
swipeView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
            @Override
            public void onScrollChanged() {
                if (webView.getScrollY() == 0) {
                    Log.d(TAG, "onScrollChanged - y=0 - make swipe refresh active");
                    swipeView.setEnabled(true);
                }else {
                    swipeView.setEnabled(false);
                    Log.d(TAG, "onScrollChanged - y is not null - swipe refresh not active");
                }
            }
        });

// swipe - after refresh do work (see above for condition)
    swipeView.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {

        @Override
        public void onRefresh() {

            Log.d(TAG, "Swipe - refresh");

            // do work ... your work method here
            getSchedule();

            // hide spinner of swiperefreshlayout
            swipeView.setRefreshing(false);

        }

    });

答案 11 :(得分:0)

解决SwipeRefreshLayoutWebView之间冲突的最可靠方法 是将触摸/滑动手势绑定到屏幕顶部的特定空间。

基于检测webview.scrollY的先前答案可能不可靠,因为某些页面的页眉位置固定,因此即使存在可滚动列表webview.scrollY也会返回0

SOURCE

  1. 创建自定义SwipeRefreshLayout
class MySwipeRefreshLayout @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null
) : SwipeRefreshLayout(context, attrs) {

    private var mDeclined = false
    private var mPrevY: Float = 0f

    override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                mPrevY = event.y

                mDeclined = false
                if (mPrevY > resources.getDimension(R.dimen.disable_swipe_after)){
                    mDeclined = true
                }
            }
            MotionEvent.ACTION_MOVE -> {
                if (mDeclined) {
                    return false
                }
            }
        }
        return super.onInterceptTouchEvent(event)
    }
}
  1. 将其应用到视图文件中
    <yourpackage.MyLimitedSwipeRefreshLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        >

        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:windowSoftInputMode="adjustResize"
            >

            <WebView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                />
        </FrameLayout>
    </yourpackage.MySwipeRefreshLayout>

答案 12 :(得分:-1)

正常使用SwipeRefreshLayout,就像使用其他视图一样,但启用嵌套滚动。

swipeRefreshLayout.setNestedScrollingEnabled(true);

答案 13 :(得分:-1)

我找到了解决方案。只需使用CoordinatorLayout作为根布局,并将layout_behavior =“@ string / appbar_scrolling_view_behavior”添加到您的SwipeRefreshLayout.It对我来说非常适合。

答案 14 :(得分:-1)

我在 webview (而不是SwipeRefreshLayout本身)上发现停用嵌套滚动为我排序了这个问题。在所有情况下都不可能这样做,但是在我的情况下。

webView.setNestedScrollingEnabled(false);