Прокрутка не работает в StickyListviewHeader с SwipeRefreshLayout

Я использую StickyHeaderListview в своем проекте для отображения содержимого и обновления списка, я использую SwipeRefreshLayout. Проблема здесь в том, что когда я пытаюсь прокрутить список вверх, он начинает обновлять список и не позволяет просматривать предыдущие элементы списка.

Я хочу, чтобы поведение было таким, чтобы список обновлялся только тогда, когда я достигал первого элемента и пытался прокручивать вверх, а не каждый раз, когда я прокручивал список.

Кто-нибудь может помочь в этом?

P.S. Для реализации SwipeRefreshLayout я ссылаюсь на этот пример


person AndyN    schedule 14.04.2014    source источник
comment
Вероятно, вы добавляете более одного представления в свой SwipeRefreshLayout. В справке относительно SwipeRefreshLayout указано следующее: этот макет должен быть сделан родительским для представления, которое будет обновлено в результате жеста, и может поддерживать только одного прямого дочернего элемента.   -  person Tobrun    schedule 15.04.2014
comment
@user1281750 user1281750 Я добавил FrameLayout внутри SwipeRefreshLayout, который содержит StickyHeadersList и пустое представление.   -  person AndyN    schedule 15.04.2014


Ответы (5)


Я столкнулся с той же проблемой при использовании StickyHeaderListview в качестве прямого потомка SwipeRefreshLayout. StickyHeaderListview на самом деле является FrameLayout, обернутым внутрь ListView. Как объяснил nitesh goel, это может привести к проблемам с canChildScrollUp(). Основываясь на примере nitesh goel, это полная версия CustomSwipeRefreshLayout, которая хорошо работает для меня:

public class CustomSwipeRefreshLayout extends SwipeRefreshLayout {

    /**
     * A StickyListHeadersListView whose parent view is this SwipeRefreshLayout
     */
    private StickyListHeadersListView mStickyListHeadersListView;

    public CustomSwipeRefreshLayout(Context context) {
        super(context);
    }

    public CustomSwipeRefreshLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public void setStickyListHeadersListView(StickyListHeadersListView stickyListHeadersListView) {
        mStickyListHeadersListView = stickyListHeadersListView;
    }

    @Override
    public boolean canChildScrollUp() {
        if (mStickyListHeadersListView != null) {
            // In order to scroll a StickyListHeadersListView up:
            // Firstly, the wrapped ListView must have at least one item
            return (mStickyListHeadersListView.getListChildCount() > 0) &&
                    // And then, the first visible item must not be the first item
                    ((mStickyListHeadersListView.getFirstVisiblePosition() > 0) ||
                            // If the first visible item is the first item,
                            // (we've reached the first item)
                            // make sure that its top must not cross over the padding top of the wrapped ListView
                            (mStickyListHeadersListView.getListChildAt(0).getTop() < 0));

            // If the wrapped ListView is empty or,
            // the first item is located below the padding top of the wrapped ListView,
            // we can allow performing refreshing now
        } else {
            // Fall back to default implementation
            return super.canChildScrollUp();
        }
    }
}
person Thuy Trinh    schedule 17.06.2014
comment
Большое спасибо за это, я хотел упомянуть будущих гуглеров, что это также работает, если вы используете какой-либо дочерний элемент AdapterView в качестве своего пользовательского представления списка и т. д. - person Daniel Wilson; 09.09.2014

Хорошо, у меня это работает. Если SwipeRefreshLayout является корнем макета, а ListView находится глубоко в иерархии (я поместил ListView в RelativeLayout вместе с пустым TextView), а не прямым дочерним элементом SwipeRefreshLayout, он не обнаружит свайп вверх. список отображается правильно.

Вы должны создать собственный класс, который расширяет SwipeRefreshLayout и переопределяет метод canChildScrollUp() в SwipRefreshLayout.

Вот пример:

public class CustomSwipeRefreshLayout extends SwipeRefreshLayout{
    private AbsListView view;

    public CustomSwipeRefreshLayout(Context context) {
        super(context);
    }

    public CustomSwipeRefreshLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public void setView(AbsListView view){
        this.view=view;
    }

    @Override
    public boolean canChildScrollUp() {
        return view.getFirstVisiblePosition()!=0;
    }
}
person nitesh goel    schedule 13.05.2014

У меня была аналогичная проблема, прямой дочерний элемент должен быть экземпляром ScrollView (или ListView). SwipeRefreshLayout будет учитывать только прокрутку прямого дочернего элемента, а не дочерний элемент этого прямого дочернего элемента. Мне удалось решить эту проблему с помощью двух SwipeRefreshLayouts.

Я разместил код на github.

person Tobrun    schedule 15.04.2014
comment
Спасибо за ответ. Я обязательно попробую это решение. +1 за попытку помощи. - person AndyN; 15.04.2014
comment
@ User22791 User22791, пожалуйста, скажите ping, мне нужна ваша помощь в отношении swiperefreshlayout. - person rupesh; 23.04.2014
comment
@ User22791 спасибо за быстрый ответ. перейдите по ссылке ниже stackoverflow.com/questions/23236650/ - person rupesh; 23.04.2014
comment
@ User22791, пожалуйста, посмотрите ссылку выше. - person rupesh; 23.04.2014

Привет, я думаю, что сделал что-то для общего использования:

public class CustomSwipeRefreshLayout extends SwipeRefreshLayout {
    private View v;

    public CustomSwipeRefreshLayout(Context context) {
        super(context);
    }

    public CustomSwipeRefreshLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public void setView(View v) {
        this.v = v;
    }

    @Override
    public boolean canChildScrollUp() {
        return this.v.canScrollVertically(-1);
    }
}

С помощью этого решения установите представление, которое вы хотите прокручивать, внутри SwipeRefreshLayout после вызова canChildScrollUp(). так :

this.refreshLayout.setView(aView);
this.refreshLayout.canChildScrollUp();

Я не тестирую это много, но если я прав, это будет работать для каждого представления в любом месте (прямой дочерний элемент или нет) в SwipeRefreshLayout.

(для меня это было SwipeRefreshLayout => RelativeLayout => SrcollView => linearLayout)

person Lucsartes    schedule 10.06.2016

Это очень простое решение:

list.setOnScrollListener(new AbsListView.OnScrollListener() {                                                   
    @Override                                                                                                   
    public void onScrollStateChanged(AbsListView view, int scrollState) {                                       
    }                                                                                                           

    @Override                                                                                                   
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {    
        int topRowVerticalPosition = (list == null || list.getChildCount() == 0) ?                              
                0 : list.getChildAt(0).getTop();                                                                
        swipeRefreshLayout.setEnabled((topRowVerticalPosition >= 0));                                           
    }                                                                                                           
});                                                                                                             

Таким образом, если вы находитесь в верхней части списка, вы сможете выполнить обновление.

person MilanNz    schedule 02.03.2015