Search code examples
androidlistviewvertical-scrolling

How can I have scrolling to last page working properly in a paginated scroll in android ListView


Attention! This question is not about dynamic loading of items into a very long ListView.

This is about adding PageUP and PageDown buttons to a ListView so that user can touch the button and scroll ListView page by page. Page means all fully and partially visible items on the screen.

I have partially implemented this in the following code, but my problem is that when I have lets say 10 items of approximately same height in the listview and 7 of them fit into the first page, then when I press PgDown button, user expects that item 8 to be on top of the screen (next page), but because there are only 10 items, ListView scrolls to the bottom of the list and because there is no extra scroll space I have item number 4 on top. What is the best solution in this situation? Should I add one item to the end of the list which will make the last page the height of the screen or there are any better options?

Here is my code:

public class cPaginatedListViewHelper {
Activity m_parentActivity;
private ListView mList;

//controls
private LinearLayout m_PagingLL;

//buttons
private ImageButton m_btnPrevPage;
private ImageButton m_btnNextPage;
private ImageButton m_btnExitPaginatedMode;


public cPaginatedListViewHelper(ListActivity mParent) {
    this.m_parentActivity = mParent;

    m_btnPrevPage=(ImageButton) mParent.findViewById(R.id.btnPrevPage);
    m_btnNextPage=(ImageButton) mParent.findViewById(R.id.btnNextPage);
    m_btnExitPaginatedMode =(ImageButton) mParent.findViewById(R.id.btnClosePage);

    if(m_btnPrevPage!=null) {
        m_btnPrevPage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                showSiblingPage(-1);
            }
        });
        m_btnPrevPage.setOnLongClickListener(new View.OnLongClickListener() {
                                         @Override
                                         public boolean onLongClick(View v) {
                                             mList.smoothScrollToPosition(0);
                                             return true;
                                         }
                                             }
        );
    }
    if(m_btnNextPage!=null) {
        m_btnNextPage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                showSiblingPage(1);
            }
        });
        m_btnNextPage.setOnLongClickListener(new View.OnLongClickListener() {
                                                 @Override
                                                 public boolean onLongClick(View v) {
                                                     mList.smoothScrollToPosition(mList.getCount());
                                                     return true;
                                                 }
                                             }
        );
    }
    m_btnExitPaginatedMode.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            setEnabled(false);
            m_PagingLL.setVisibility(View.GONE);
        }
    });

    mList=mParent.getListView();
    m_PagingLL = (LinearLayout) mParent.findViewById(R.id.pageControls);

}

public void updateControlsVisibility()
{
    ViewTreeObserver observer = mList.getViewTreeObserver();
    observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            if (willMyListScroll()) {
                boolean psm = isEnabled();
                //enable or disable
                m_PagingLL.setVisibility( psm ? View.VISIBLE : View.GONE);

                ((View)mList).setVerticalScrollbarPosition(psm ? View.SCROLLBAR_POSITION_LEFT: View.SCROLLBAR_POSITION_RIGHT);

            }
            else
            {
                m_PagingLL.setVisibility(View.GONE);
                ((View)mList).setVerticalScrollbarPosition(View.SCROLLBAR_POSITION_RIGHT);
            }
        }
    });
}

private boolean willMyListScroll() {
    try {
        int pos = mList.getLastVisiblePosition();
        if (mList.getChildAt(pos).getBottom() > mList.getHeight()) {
            return true;
        } else {
            return false;
        }
    } catch (Exception e) {
        e.printStackTrace();

    }
    return false;
}


private void showSiblingPage(int shift)
{
    if(mList!=null) {
        int iScrollPageHeight = mList.getHeight();
        mList.scrollListBy(iScrollPageHeight * shift);
    }
}


public void setEnabled(boolean psm) {
    MyApp.Pref.edit().putBoolean("PSModeEnabled", psm).commit();
}

public boolean isEnabled(){
    return MyApp.Pref.getBoolean("PSModeEnabled", false);
}


public void pagedScrollEnableDisable() {
    boolean pagingEnabled = isEnabled();
    pagingEnabled=!pagingEnabled;
    setEnabled(pagingEnabled);
    m_PagingLL.setVisibility( pagingEnabled ? View.VISIBLE : View.GONE);
    updateControlsVisibility();
}

}


Solution

  • I finished up with using ListView's footer with variable height as shown in the following code:

                    LayoutInflater inflater = m_parentActivity.getLayoutInflater();
                    m_footerView = inflater.inflate(R.layout.listview_paged_overscroll, mList, false );
                    ViewGroup.LayoutParams lp =m_footerView.getLayoutParams();
    
                    if(m_tvPageNum!=null) recalcPagination();
                    if(lp!=null) lp.height = m_extraScrollFooterHeight;
                    int iFooters = mList.getFooterViewsCount();
                    if(iFooters==0) mList.addFooterView(m_footerView);