How implement sticky footer in recyclerview

后端 未结 8 1784
时光说笑
时光说笑 2021-02-04 02:52

I have RecyclerView and I need next behavior:

  • if there are a lot of items (more then fits screen) - footer is last item
  • if few item/no item - footer is lo
8条回答
  •  花落未央
    2021-02-04 03:19

    Improvising on Dmitriy Korobeynikov and solving the problem of calling notify dataset changed

    public class StickyFooterItemDecoration extends RecyclerView.ItemDecoration {
    
      @Override
      public void getItemOffsets(Rect outRect, final View view, final RecyclerView parent,
          RecyclerView.State state) {
    
        int position = parent.getChildAdapterPosition(view);
        int adapterItemCount = parent.getAdapter().getItemCount();
        if (adapterItemCount == RecyclerView.NO_POSITION || (adapterItemCount - 1) != position) {
          return;
        }
        outRect.top = calculateTopOffset(parent, view, adapterItemCount);
      }
    
    
      private int calculateTopOffset(RecyclerView parent, View footerView, int itemCount) {
        int topOffset =
            parent.getHeight() - parent.getPaddingTop() - parent.getPaddingBottom()
                - visibleChildHeightWithFooter(parent, footerView, itemCount);
        return topOffset < 0 ? 0 : topOffset;
      }
    
    
    
      private int visibleChildHeightWithFooter(RecyclerView parent, View footerView, int itemCount) {
        int totalHeight = 0;
        int onScreenItemCount = Math.min(parent.getChildCount(), itemCount);
        for (int i = 0; i < onScreenItemCount - 1; i++) {
          RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) parent.getChildAt(i)
              .getLayoutParams();
          int height =
              parent.getChildAt(i).getHeight() + layoutParams.topMargin
                  + layoutParams.bottomMargin;
          totalHeight += height;
        }
        int footerHeight = footerView.getHeight();
        if (footerHeight == 0) {
          fixLayoutSize(footerView, parent);
          footerHeight = footerView.getHeight();
        }
        footerHeight = footerHeight + footerView.getPaddingBottom() + footerView.getPaddingTop();
    
        return totalHeight + footerHeight;
      }
    
      private void fixLayoutSize(View view, ViewGroup parent) {
        // Check if the view has a layout parameter and if it does not create one for it
        if (view.getLayoutParams() == null) {
          view.setLayoutParams(new ViewGroup.LayoutParams(
              ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
        }
    
        // Create a width and height spec using the parent as an example:
        // For width we make sure that the item matches exactly what it measures from the parent.
        //  IE if layout says to match_parent it will be exactly parent.getWidth()
        int widthSpec = View.MeasureSpec.makeMeasureSpec(parent.getWidth(), View.MeasureSpec.EXACTLY);
        // For the height we are going to create a spec that says it doesn't really care what is calculated,
        //  even if its larger than the screen
        int heightSpec = View.MeasureSpec
            .makeMeasureSpec(parent.getHeight(), View.MeasureSpec.UNSPECIFIED);
    
        // Get the child specs using the parent spec and the padding the parent has
        int childWidth = ViewGroup.getChildMeasureSpec(widthSpec,
            parent.getPaddingLeft() + parent.getPaddingRight(), view.getLayoutParams().width);
        int childHeight = ViewGroup.getChildMeasureSpec(heightSpec,
            parent.getPaddingTop() + parent.getPaddingBottom(), view.getLayoutParams().height);
    
        // Finally we measure the sizes with the actual view which does margin and padding changes to the sizes calculated
        view.measure(childWidth, childHeight);
    
        // And now we setup the layout for the view to ensure it has the correct sizes.
        view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
      }
    }
    

提交回复
热议问题