使用CWAC Endless Adapter加载内容后,ListView滚动位置未保留

时间:2014-08-18 12:30:57

标签: android listview scroll

更新

基本上,bbrakenhoff回答了我的问题,但还有一件事需要解决。如何更新EndlessFeedAdapter(mEndlsFidAdptr)的内容?我需要清除该项目然后重新加载。我正在使用CWAC EndlessAdapater。是否有清除内容的技巧或者编写方法更容易?完成此操作后,滚动位置应该是维护。


我从服务器获取数据并在内容更改时更新EndlessFeedAdapter。每次我更新我的适配器并重新加载内容。问题是重新加载后我的列表会跳回到顶部,因为我的滚动位置没有被保持。我已经广泛尝试了setSelection和setSelectionFromTop,但没有得到积极的结果。

如何在更新适配器后保持滚动位置?

我一直在寻找答案的论坛,但似乎没有任何工作。

我尝试了所有这些:Maintain/Save/Restore scroll position when returning to a ListView

这不起作用:

int index = mList.getFirstVisiblePosition();
View v = mList.getChildAt(0);
int top = (v == null) ? 0 : v.getTop();


 // restore index and position
mList.setSelectionFromTop(index, top);

也不是这样:

// Save ListView state
Parcelable state = listView.onSaveInstanceState();

// Set new items
listView.setAdapter(adapter);

// Restore previous state (including selected item index and scroll position)
listView.onRestoreInstanceState(state);

也不是其他解决方案,例如设置runnable或设置scrollPositionY。设置notifyDataChanged不起作用,因为我从不同的列表加载。

我的代码:

private void showFeed() {

    if (mFeedActivity.mInFeed) {
        mQuickReturnView.setVisibility(View.VISIBLE);
    } else {
        mQuickReturnView.setVisibility(View.GONE);
    }                                  

    Activity actvt= getActivity();
    if (actvt == null || mFeedListView == null) return;

    actvt.invalidateOptionsMenu();

    mFeedListView.setVisibility(View.VISIBLE);

    //updated with help from response
    if (mAdapter == null){
        mAdapter = new FeedAdapter(actvt, 0, mFeed.getItems().getFeedItemList(), this);
    } else {
        mAdapter.clear();
        mAdapter.addAll(mFeed.getItems().getFeedItemList());
        mAdapter.notifyDataSetChanged();
    }

    mEndlsFidAdptr = new EndlessFeedAdapter(actvt, mAdapter, R.layout.progress_row, mFeed.isShowMoreBar(),

    mEndlsFidAdptr.setRunInBackground(false);

    //Parcelable state = mFeedListView.onSaveInstanceState();
    mFeedListView.setAdapter(mEndlsFidAdptr);
    //mFeedListView.onRestoreInstanceState(state);



    mFeedListView.setSelectionFromTop(mFirstVisibleItem, mVisibleItemOffset);

    if(!(mFeedScope.equalsIgnoreCase(FeedScope.BOOKMARKS.xmlValue()) ||
            mFeedScope.equalsIgnoreCase(FeedScope.DOCUMENT.xmlValue()) ||
            mFeedScope.equalsIgnoreCase(FeedScope.NOTIFICATIONS.xmlValue()) ||
            mFeedScope.equalsIgnoreCase(FeedScope.RECEIVED_TASKS.xmlValue()) ||
            mFeedScope.equalsIgnoreCase(FeedScope.SEND_TASKS.xmlValue()))) {

  mFeedListView.getViewTreeObserver().addOnGlobalLayoutListener(mGlobalLayoutListener);


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

                mCanShowHide = scrollState == SCROLL_STATE_FLING;

            }


            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

                View v = mFeedListView.getChildAt(0);
                //View v = null;
                if(!mFeedActivity.mInFeed || v == null)
                    return;

                int top = v.getTop();

                if(mIsAnimating) {
                    mVisibleItemOffset = top;
                    mFirstVisibleItem = firstVisibleItem;
                    return;
                }

                boolean hide = false;
                boolean show = false;
                float stickyHeight = getResources().getDimension(R.dimen.sticky_height);

                if(firstVisibleItem == mFirstVisibleItem) {
                    if((top + stickyHeight) < mVisibleItemOffset) {
                        // Content scrolled down
                        // if shown then hide quickactionview
                        if(mQuickReturnShown) {
                            hide = true;
                        }

                    } else if (top > mVisibleItemOffset) {
                        // Content scrolled up
                        // if hidden then show quickactionview
                        if(!mQuickReturnShown) {
                            show = true;
                        }

                    }

                } else if(firstVisibleItem > mFirstVisibleItem) {
                    // Content scrolled down
                    // if shown then hide quickactionview
                    if(mQuickReturnShown) {
                        hide = true;
                    }

                } else if (firstVisibleItem < mFirstVisibleItem) {
                    // Content scrolled up
                    // if hidden then show quickactionview
                    if(!mQuickReturnShown) {
                        show = true;
                    }
                }

                if((show && mCanShowHide) || (top == 0 && !mQuickReturnShown)) {
                    mTranslateAnimation = new TranslateAnimation(0, 0, -mQuickReturnHeight, 0);
                    mTranslateAnimation.setDuration(DURATION_MILLIS);
                    mTranslateAnimation.setAnimationListener(new Animation.AnimationListener() {
                        @Override
                        public void onAnimationStart(Animation animation) {
                            mIsAnimating = true;
                        }

                        @Override
                        public void onAnimationEnd(Animation animation) {
                            mIsAnimating = false;
                            mQuickReturnShown = true;
                            mQuickReturnView.setVisibility(View.VISIBLE);
                        }

                        @Override
                        public void onAnimationRepeat(Animation animation) {

                        }
                    });

                    mQuickReturnView.startAnimation(mTranslateAnimation);
                }

                if(hide) {
                    mTranslateAnimation = new TranslateAnimation(0, 0, 0, -mQuickReturnHeight);
                    mTranslateAnimation.setDuration(DURATION_MILLIS);
                    mTranslateAnimation.setAnimationListener(new Animation.AnimationListener() {
                        @Override
                        public void onAnimationStart(Animation animation) {
                            mIsAnimating = true;
                        }

                        @Override
                        public void onAnimationEnd(Animation animation) {
                            mIsAnimating = false;
                            mQuickReturnShown = false;
                            mQuickReturnView.setVisibility(View.GONE);
                        }

                        @Override
                        public void onAnimationRepeat(Animation animation) { }
                    });


                    mQuickReturnView.startAnimation(mTranslateAnimation);
                }

                mVisibleItemOffset = top;
                mFirstVisibleItem = firstVisibleItem;
            }
        });
    } else {
        mFeedListView.setOnScrollListener(null);

    }

    mFeedListView.setSelectionFromTop(mFirstVisibleItem, mVisibleItemOffset);

    //mFeedListView.scrollTo(mCurrentX,mCurrentY);

    if(mFeed.getItems().getFeedItemList().size() == 0) {
        mEmptyFeedView.setVisibility(View.VISIBLE);
    }
}

感谢任何帮助!

3 个答案:

答案 0 :(得分:2)

每次收到新数据时,您是否正在调用方法showFeed()?如果是,那么也许您可以尝试重新填充适配器,而不是每次都分配一个新适配器。

我不确切地知道你在适配器中做了什么,所以我会告诉你我是如何在我的一个应用程序中做到的。

在我的Activity / Fragment中,当我想用​​新项目更新列表时,我这样做:

private void refreshCalendar(ArrayList<CalendarDay> newCalendar) {
    if (mAdapter == null) {
        mAdapter = new CalendarAdapter(getActivity(), newCalendar);
        mExpandableListView.setAdapter(mAdapter);
    }
    else {
        mAdapter.refill(newCalendar);
    }

    restoreInstanceState();
}

在适配器中:

public void refill(ArrayList<CalendarDay> newCalendar) {
    mCalendar.clear();
    mCalendar.addAll(newCalendar);
    notifyDataSetChanged();
}

答案 1 :(得分:1)

也许您可以尝试删除此行?

  mFeedListView.setSelectionFromTop(mFirstVisibleItem, mVisibleItemOffset);

修改:您在代码中使用此行两次。

编辑:在您问题的代码中,您只刷新mAdapter而不是mEndlsFidAdptr。那个仍然被分配一个新的。每次为ListView分配一个新的适配器时,它都会滚动回到顶部。

答案 2 :(得分:0)

所以解决方案并不是我正在寻找的合理位置。非常感谢bbrakenhoff指出我正确的方向!

我的类showFeed()是从另一个名为downloadFeed()的类调用的,我的滚动位置没有被维护,因为downloadFeed()在刷新时只加载5个项目,因此即使我保持正确的滚动位置,它也是不可见。

虽然如果其他人有这个问题可能是一个长镜头 - 修复只需创建一个变量来保存用户执行onClick事件时可滚动列表的总大小。然后当再次调用downloadFeed()时,有更多项目要下载而不是默认5.然后,当现在可见项目存在时,可以维护滚动位置。

我最终使用了mFeedListView.setSelectionFromTop(firstVisibleItem,positionOffset)