我正在尝试将SwipeRefreshLayout与WebView一起使用。
我遇到的问题是在页面中间,当用户向下滚动时,不必要的刷新就会开始。
如何在webview的滚动位置位于顶部时才进行刷新事件。 (即,他正在查看页面的顶部)?
答案 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();
}
}
在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;
}
}
答案 2 :(得分:7)
只需使用Fragment
实施您的Activity
或ViewTreeObserver.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
方法,因此它适用于ListView
和WebView
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();
}
}
(如上所述,canScrollVertically
是View
方法,因此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)
解决SwipeRefreshLayout
与WebView
之间冲突的最可靠方法
是将触摸/滑动手势绑定到屏幕顶部的特定空间。
基于检测webview.scrollY
的先前答案可能不可靠,因为某些页面的页眉位置固定,因此即使存在可滚动列表webview.scrollY
也会返回0
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)
}
}
<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);