Recycleview imitates the list of items in Ruixing coffee menu

  • First of all, we need to understand that Recycleview's ItemDecoration is very powerful. You can use it to realize listview's segmentation lines, suspension windows, and even some very cool animations.
  • First look at the renderings


  • onDraw(): similar to the onDraw of ordinary view, which is to draw things on the canvas.
  • onDrawOver(): Based on the redraw point on onDraw, over means.
  • getItemOffsets():Recycleview can get the spacing of each item through it, so you only need to control the spacing, and use onDrawOver to draw what you want to draw in the spacing.

    To realize this idea, we only need to reserve the height we want to vacate through getItemOffsets in the specified number of rows, and then draw the desired view through onDrawOver.

One: manually construct data format, as follows, return to list

Goods goods1 = new Goods("Popularity TOP", "Zhengguo latte 1", "Y27", "default:large/Monosaccharide/heat");
Goods goods99 = new Goods("Popularity TOP", "Zhengguo latte 2", "Y27", "default:large/Monosaccharide/heat");
Goods goods91 = new Goods("Popularity TOP", "Zhengguo latte 3", "Y27", "default:large/Monosaccharide/heat");
Goods goods2 = new Goods("Master coffee", "Latte", "Y27", "default:large/Monosaccharide/heat");
Goods goods3 = new Goods("Master coffee", "Vanilla Latte", "Y24", "default:large/Monosaccharide/heat");
Goods goods4 = new Goods("Master coffee", "Caramel Latte", "Y26", "default:large/Half sugar/heat");
List<Goods> list = new ArrayList<>();

II. Write your own ItemDecoration

  • getItemOffsets only need to reserve a height in the first data of each array, such as the first popularity TOP and the first master coffee.
The first one must be reserved name Space reserved if it is not equal to the previous one
public boolean isParent(int position) {
    if (position == 0) return true;
        if (!list.get(position).getType().equals(list.get(position - 1).getType()))
            return true;
    return false;
//Is it the last item currently
protected boolean lastOneInGroup(int position) {
        String parentName = mDecorListener.parentName(position);
        String nextGroupName;
        try {
            nextGroupName = mDecorListener.parentName(position + 1);
        } catch (Exception e) {
            nextGroupName = null;
        if (nextGroupName == null) {
            return false;
        return !TextUtils.equals(parentName, nextGroupName);//The name of the next line is different, indicating that the current line is the last one

//Judging from the isParent, it is the first one to return the height size you want to reserve. Otherwise, it means the space 0 is not needed
  public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        int position = parent.getChildAdapterPosition(view);
        if (parent.getLayoutManager() instanceof LinearLayoutManager && mDecorListener.isParent(position)) {
   = decorationHeight;
        } = 0;
  • Draw your view on the reserved space
    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
        super.onDrawOver(c, parent, state);
        final int itemCount = state.getItemCount(); whole item Quantity
        final int childCount = parent.getChildCount(); Number of visible separation lines excluding hovering
        final int left = parent.getPaddingLeft();
        final int right = parent.getWidth() - parent.getPaddingRight();
        for (int i = 0; i < childCount; i++) {
            View childView = parent.getChildAt(i);
            int position = parent.getChildAdapterPosition(childView);//This is the position of each line currently visible, starting from 0
            //The first one by default is a Group
            if (mDecorListener.isParent(position) || i == 0) {//The first position in and the first visible position have this hover
                //Paint suspension,
                int bottom = Math.max(decorationHeight, (childView.getTop() + parent.getPaddingTop()));
                //Determine the bottom of the first suspended Group at the top, get the item height and the specified height, and only select an appropriate height to define the dividing line
                if (position + 1 < itemCount) {
                    //The first View in the next group is close to the head
                    int viewBottom = childView.getBottom();
                    if (lastOneInGroup(position) && viewBottom < bottom) {
                        bottom = viewBottom;                    //If this is turned off, it will be covered, and the top effect will be lost. In fact, the viewBottom will gradually become 0, so that the dynamic placement of the floating bar that is about to disappear looks like the next floating bar on top
                drawDecoration(c, position, left, right, bottom, parent);
                stickyHeaderPosArray.put(position, bottom);

    private void drawDecoration(Canvas c, int position, int left, int right, int bottom, RecyclerView parent) {
        c.drawRect(left, bottom - decorationHeight, right, bottom, mGroutPaint);
        Paint.FontMetrics fm = mTextPaint.getFontMetrics();
        //Text vertically centered
        float baseLine = bottom - (decorationHeight - (fm.bottom - / 2 - fm.bottom;
        //Get text width
        mSideMargin = Math.abs(mSideMargin);
        c.drawText(mDecorListener.parentName(position), left + mSideMargin, baseLine, mTextPaint);//x-axis, baseLine
        Rect rect = new Rect();//To get the properties of the current text
        mTextPaint.getTextBounds(mDecorListener.parentName(position), 0, mDecorListener.parentName(position).length(), rect);
        //Draw that horizontal line
        c.drawLine(left + mSideMargin * 2 + rect.width(), baseLine - rect.height() / 2, parent.getWidth() -
                mSideMargin, baseLine - rect.height() / 2, mTextPaint);



Tags: Android Windows

Posted on Wed, 04 Dec 2019 08:14:08 -0500 by ScotDiddle