Избегайте SwipeRefresh при быстрой прокрутке в Android

У меня есть ListView имеющий fastScroll всегда включен и SwipeRefresh реализация. Когда я смахиваю список вниз, он обновляет список. Моя проблема fastScroll, Если в списке есть первый видимый элемент или, скажем, в начале, то прокрутите fastScrollThumb вниз, это делает Swipe эффект не прокручивать вниз. Есть ли в любом случае / решение, что если я нажму fastScrollThumb, то это не должно делать Swipe Эффект обновления скорее должен прокручиваться вниз, так как это естественное поведение.

Отредактированный мой 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>

мой Logic for onScroll для включения / выключения SwipeRefresh является:

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

        }
    }
});

2 ответа

Решение

Я просто заглянул в документацию SwipeRefreshLayout и я думаю, что они упоминают, что вы ищете:

... Если слушатель определяет, что обновления не должно быть, он должен вызвать setRefreshing(false) отменить любую визуальную индикацию обновления. Если действие хочет показать только анимацию прогресса, оно должно вызвать setRefreshing(true), Чтобы отключить жест и анимацию прогресса, позвоните setEnabled(false) на вид.

Так что у вас есть несколько вариантов, я бы сначала попробовал поиграться с setEnabled() или же setRefreshing(), но чтобы правильно использовать эти методы, мы должны сначала определить, ListView быстрая прокрутка. Нет слушателя или чего-либо еще для быстрой прокрутки, но вы можете получить состояние через отражение! На основании этого превосходного и серьезно недооцененного ответа я написал FastScrollListener который может быть использован так же, как 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) {

    }
});

Вы также можете попробовать позвонить setRefreshing() вместо setEnabled() если setEnabled() не работает

И вот код 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);
}

Я надеюсь, что смогу помочь вам, и если у вас есть какие-либо дополнительные вопросы, пожалуйста, не стесняйтесь спрашивать!


РЕДАКТИРОВАТЬ: Попробуйте это, но я сомневаюсь, что это будет работать:

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

Быстрая прокрутка в переработке просмотра была добавлена ​​в API 26. https://developer.android.com/topic/libraries/support-library/revisions.

Если вы хотите использовать его, предварительно используйте API.

https://github.com/L4Digital/FastScroll

Эта библиотека имеет встроенную функцию fastscroll и прослушиватель прокрутки, который может отключить макет обновления при прокрутке.

Разработчик решает проблему здесь:

https://github.com/L4Digital/FastScroll/issues/14

Другие вопросы по тегам