在android中快速滚动时避免SwipeRefresh [英] Avoid SwipeRefresh while fastScrolling in android

查看:15
本文介绍了在android中快速滚动时避免SwipeRefresh的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 ListView 始终启用 fastScrollSwipeRefresh 实现.当我向下滑动列表时,它会刷新列表.我的问题是 fastScroll.如果列表的第一项可见或在其初始顶部,那么如果向下滚动 fastScrollThumb,它会执行 Swipe 效果而不是向下滚动.无论如何/解决方案,如果我按下 fastScrollThumb ,那么它不应该做 Swipe 刷新效果,而是应该向下滚动,因为它是自然行为.

I have a ListView having fastScroll always enabled and SwipeRefresh implementation. When i swipe the list downward, it refreshes the list. My problem is fastScroll. If the list has its first item visible or say at its initial top, then if scroll the fastScrollThumb downward, it does the Swipe effect not the scroll down. Is there anyway/solution that if i press the fastScrollThumb , then it should not do Swipe refresh effect rather it should scroll down as it natural behavior.

已编辑我的 XML Layout 如下:

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.v4.widget.SwipeRefreshLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/swipe_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/white" >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <RelativeLayout
            android:id="@+id/buttons_layout"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="10dp"> 

            <ImageView
                android:id="@+id/SubmitButton"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@drawable/neoo_tab_selector" />

        </RelativeLayout>


        <ListView
            android:id="@id/android:list"
            style="@style/NeeoContactListView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_below="@+id/buttons_layout"
            android:layout_marginTop="10dp" />
    </RelativeLayout>

</android.support.v4.widget.SwipeRefreshLayout>

我用于启用/禁用 SwipeRefreshonScroll 逻辑是:

My Logic for onScroll for enabling/disabling the SwipeRefresh is :

    getListView().setOnScrollListener(new OnScrollListener() {

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        boolean enable = false;
        if(getListView() != null && getListView().getChildCount() > 0){
            // check if the first item of the list is visible
            boolean firstItemVisible = getListView().getFirstVisiblePosition() == 0;
            // check if the top of the first item is visible
            boolean topOfFirstItemVisible = getListView().getChildAt(0).getTop() == 0;
            // enabling or disabling the refresh layout
            enable = firstItemVisible && topOfFirstItemVisible;
        }
        if(enable){
            enableSwipe();

        }else{
            disableSwipe();

        }
    }
});

推荐答案

我刚刚查看了 SwipeRefreshLayout文档,我认为他们提到了您要查找的内容:

I just looked into the documentation of the SwipeRefreshLayout and I think they mention what you are looking for:

... 如果侦听器确定不应刷新,则必须调用 setRefreshing(false) 取消任何视觉指示刷新.如果一个活动希望只显示进度动画,它应该调用 setRefreshing(true).禁用手势和进度动画,在视图上调用 setEnabled(false).

... If the listener determines there should not be a refresh, it must call setRefreshing(false) to cancel any visual indication of a refresh. If an activity wishes to show just the progress animation, it should call setRefreshing(true). To disable the gesture and progress animation, call setEnabled(false) on the view.

所以你有几个选择,我会首先尝试使用 setEnabled()setRefreshing(),但要正确使用这些方法,我们首先需要能够检测 ListView 是否正在快速滚动.没有侦听器或任何用于快速滚动的东西,但您可以通过反射获得状态!基于这个优秀但被严重低估的答案,我写了一个FastScrollListener 可以像 OnScrollListener 一样使用:

So you have a few options, I would first try playing around with setEnabled() or setRefreshing(), but to properly use those methods we first need to be able to detect if the ListView is fast scrolling. There is no listener or anything for fast scrolling but you can get the state through reflection! Based on this excellent and seriously underrated answer I have written a FastScrollListener which can be used just like a OnScrollListener:

this.listView.setFastScrollEnabled(true);
this.listView.setOnScrollListener(new FastScrollListener(this.listView) {

    @Override
    protected void onFastScrollStateChanged(AbsListView view, FastScrollState state) {
        // This line disabled the SwipeRefreshLayout  
        // whenever the user is fast scrolling
        swipeRefreshLayout.setEnabled(state != FastScrollState.DRAGGING);
    }

    @Override
    protected void onFastScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

    }
});

如果 setEnabled() 不起作用,您也可以尝试调用 setRefreshing() 而不是 setEnabled().

You could also try calling setRefreshing() instead of setEnabled() if setEnabled() doesn't work.

这里是FastScrollListener的代码:

public abstract class FastScrollListener implements AbsListView.OnScrollListener {

    private final int STATE_DRAGGING;
    private final int STATE_VISIBLE;
    private final int STATE_NONE;

    public enum FastScrollState {
        DRAGGING,
        VISIBLE,
        NONE,
        UNKNOWN
    }

    private FastScrollState fastScrollState = FastScrollState.UNKNOWN;
    private Field stateField;
    private Object mFastScroller;

    public FastScrollListener(AbsListView listView) {
        try {
            final Field fastScrollerField = AbsListView.class.getDeclaredField("mFastScroller");
            fastScrollerField.setAccessible(true);
            mFastScroller = fastScrollerField.get(listView);

            final Field stateDraggingField = mFastScroller.getClass().getDeclaredField("STATE_DRAGGING");
            stateDraggingField.setAccessible(true);
            STATE_DRAGGING = stateDraggingField.getInt(mFastScroller);

            final Field stateVisibleField = mFastScroller.getClass().getDeclaredField("STATE_VISIBLE");
            stateVisibleField.setAccessible(true);
            STATE_VISIBLE = stateVisibleField.getInt(mFastScroller);

            final Field stateNoneField = mFastScroller.getClass().getDeclaredField("STATE_NONE");
            stateNoneField.setAccessible(true);
            STATE_NONE = stateNoneField.getInt(mFastScroller);

            stateField = mFastScroller.getClass().getDeclaredField("mState");
            stateField.setAccessible(true);
            fastScrollState = getFastScrollState();

        } catch (NoSuchFieldException e) {
            throw new IllegalStateException("Could not find required fields for fast scroll detection!", e);
        } catch (IllegalAccessException e) {
            throw new IllegalStateException("Could not find required fields for fast scroll detection!", e);
        }
    }

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        updateFastScrollState(view);
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        updateFastScrollState(view);
        updateFastScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
    }

    private void updateFastScrollState(AbsListView view) {
        if (stateField != null) {
            final FastScrollState state = getFastScrollState();
            if (fastScrollState != state) {
                fastScrollState = state;
                onFastScrollStateChanged(view, state);
            }
        }
    }

    private void updateFastScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        if(fastScrollState == FastScrollState.DRAGGING) {
            onFastScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
        }
    }

    private FastScrollState getFastScrollState() {

        try {
            final int state = stateField.getInt(mFastScroller);

            if (state == STATE_DRAGGING) {
                return FastScrollState.DRAGGING;
            }

            if (state == STATE_VISIBLE) {
                return FastScrollState.VISIBLE;
            }

            if (state == STATE_NONE) {
                return FastScrollState.NONE;
            }

            return FastScrollState.UNKNOWN;
        } catch (IllegalAccessException e) {
            throw new IllegalStateException("Could not read fast scroll state!", e);
        }
    }

    protected abstract void onFastScrollStateChanged(AbsListView view, FastScrollState state);

    protected abstract void onFastScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount);
}

希望我能帮到你,如果你有任何其他问题,请随时提问!

I hope I could help you and if you have any further questions please feel free to ask!

试试这个,但我怀疑它会起作用:

Try this, but I doubt it will work:

@Override
protected void onFastScrollStateChanged(AbsListView view, FastScrollState state) {
    boolean enable = false;
    if (getListView().getChildCount() > 0) {
        boolean firstItemVisible = getListView().getFirstVisiblePosition() == 0;
        boolean topOfFirstItemVisible = getListView().getChildAt(0).getTop() == 0;
        enable = firstItemVisible && topOfFirstItemVisible;
    }
    refreshLayout.setEnabled(enable);
}

这篇关于在android中快速滚动时避免SwipeRefresh的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆