Listview - Footer at the bottom of screen

2019-01-25 06:52发布

问题:

I have a ListView with a footer added with listview.addFooterView(footerView);

All works as expected excepted in one case: when my listview's items doesn't fill the whole screen, I would like the footer to be at the bottom of the screen, instead of being in the middle. Is there a way to do this easily? Or should I change my layout?

Thanks

EDIT: that might help (this is what I want)

回答1:

If you want it to always be at the bottom of the screen, no matter how long your ListView is, then get rid of listview.addFooterView(footerView); and use a RelativeLayout. Give yourListView` the property

 android:layout_alignParentTop="true"

and give the property to your footer

 android:layout_alignParentBottom="true"

If this doesn't solve your problem then please be a little more specific about what you want and provide a picture of what you want if possible.

Edit

After reading the comments this might work. There might be an easier way but you could do something like

     listView.post(new Runnable()
     {       
         public void run()
        {
            int numItemsVisible = listView.getLastVisiblePosition() - 
            listView.getFirstVisiblePosition();
            if (itemsAdapter.getCount() - 1 > numItemsVisible)
            {   
                 // set your footer on the ListView
            }
            else
            {
                 footerView.setVisibility(View.VISIBLE);
            }
         }

footerView would be a custom layout that you would create with the properties I referenced above. This should set that to visible if the items aren't more than can fit on the screen. If they are more than can fit then you apply the footer view on the ListView as you are now. This might not be the best way but its the first thing that comes to mind. You would run this code just before you set the Adapter.



回答2:

You cannot use ListView footer as footer for the whole layout. You're better off with RelativeLayout as root element for your layout, and then a direct child of it containing the footer view with the attribute: android:layout_alignParentBottom="true"



回答3:

In addition to @codeMagic response, you could add a listener to check when your adapter gets updated and then update the footer

registerDataSetObserver(new DataSetObserver() {
            @Override
            public void onChanged() {
                super.onChanged();
                updateSmartFooter();
            }
        });

where updateSmartFooter is the function he described

 private void updateSmartFooter {
     listView.post(new Runnable()
     {       
         public void run()
        {
            int numItemsVisible = listView.getLastVisiblePosition() - 
            listView.getFirstVisiblePosition();
            if (itemsAdapter.getCount() - 1 > numItemsVisible)
            {   
                 // set your footer on the ListView
            }
            else
            {
                 footerView.setVisibility(View.VISIBLE);
            }
         }
      }
}


回答4:

After spent a lot of time to research, I found the best solution for it. Please have a look at: https://stackoverflow.com/a/38890559/6166660 and https://github.com/JohnKuper/recyclerview-sticky-footer

For details:

  • Create a StickyFooterItemDecoration extends RecyclerView.ItemDecoration like the example code below.
  • After that, set ItemDecoration to your recyclerView:

recyclerListView.addItemDecoration(new StickyFooterItemDecoration());

---------------------------------------

 public class StickyFooterItemDecoration extends RecyclerView.ItemDecoration {

    private static final int OFF_SCREEN_OFFSET = 5000;

    @Override
    public void getItemOffsets(Rect outRect, final View view, final RecyclerView parent, RecyclerView.State state) {
        int adapterItemCount = parent.getAdapter().getItemCount();
        if (isFooter(parent, view, adapterItemCount)) {
            if (view.getHeight() == 0 && state.didStructureChange()) {
                hideFooterAndUpdate(outRect, view, parent);
            } else {
                outRect.set(0, calculateTopOffset(parent, view, adapterItemCount), 0, 0);
            }
        }
    }

    private void hideFooterAndUpdate(Rect outRect, final View footerView, final RecyclerView parent) {
        outRect.set(0, OFF_SCREEN_OFFSET, 0, 0);
        footerView.post(new Runnable() {
            @Override
            public void run() {
                parent.getAdapter().notifyDataSetChanged();
            }
        });
    }

    private int calculateTopOffset(RecyclerView parent, View footerView, int itemCount) {
        int topOffset = parent.getHeight() - visibleChildsHeightWithFooter(parent, footerView, itemCount);
        return topOffset < 0 ? 0 : topOffset;
    }

    private int visibleChildsHeightWithFooter(RecyclerView parent, View footerView, int itemCount) {
        int totalHeight = 0;
        int onScreenItemCount = Math.min(parent.getChildCount(), itemCount);
        for (int i = 0; i < onScreenItemCount - 1; i++) {
            totalHeight += parent.getChildAt(i).getHeight();
        }
        return totalHeight + footerView.getHeight();
    }

    private boolean isFooter(RecyclerView parent, View view, int itemCount) {
        return parent.getChildAdapterPosition(view) == itemCount - 1;
    }
}