Now the use of the list in the project I write is basically all RecyclerView, and the use of the list will be very likely to use the function of the dividing line. In use before RecyclerView partition function, is using RecyclerView set the background color and background color difference of each Item, and inherit RecyclerView ItemDecoration, And simply rewrite getItemOffsets (Rect outRect, View View, RecyclerView parent, recyclerView. State State) method can achieve the effect. Simply implement a splitter effect code as follows

public void getItemOffsets (Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { switch (mOrientation) { case LinearLayoutManager.HORIZONTAL: outRect.right += mSpace; if (parent.getChildAdapterPosition (view) == 0) outRect.left += mSpace; break; case LinearLayoutManager.VERTICAL: outRect.bottom += mSpace; if (parent.getChildAdapterPosition (view) == 0) outRect.top += mSpace; break; }}Copy the code

This will achieve the simplest effect of a split line. But today when I was writing the project, I encountered the situation that the color of the dividing line might change. So this simple way is not enough.

First of all, Google found that Item decoration can do much more than that. It can also customize more cool effects. It can not only draw a dividing line effect under the Item, but also stamp on the Item. To customize more effects, override the other two methods of ItemDecoration

onDraw(Canvas c, RecyclerView parent, RecyclerView.State state)

and

onDrawOver (Canvas c, RecyclerView parent, RecyclerView.State state)

The onDraw method executes before the onDraw method of the Item, so what it draws is always below the Item. In the onDraw draw scope is set for the Divider and drawn to the canvas. The range of decoration can be beyond the range set in getItemOffsets, but because decoration is drawn below childView, it is not visible, but overDraw exists. The onDraw over method is executed after the Item’s onDraw, so the onDraw over method is on top of the Item. I studied the onDrawOver method carefully, and it was like discovering a new world. In this project, there is a list that needs to show a picture on the left, four lines of text description in the middle, and then another picture on the right, but this picture should be covered with text and the effect is similar to the following!

I originally pieced together this effect using an XML layout file. However, after a careful study of the onDrawOver method, it is found that this effect can also be achieved with onDrawOver. Of course, the XML file has a lot fewer lines of code and is definitely more efficient to load, but the most important thing is that it feels like the B grid has suddenly gone up a lot

Below is the complete code for customizing ItemDecoration

public class MyItemDecoration extends RecyclerView.ItemDecoration { private Drawable mDivider; private int mSize; private int mOrientation; private Paint mPaint; private Bitmap bitmap; public MyItemDecoration (Context context, int color, int drawableId, int size, int orientation) { mDivider = new ColorDrawable (color); mSize = size; mOrientation = orientation; bitmap = BitmapFactory.decodeResource (context.getResources (), drawableId); mPaint = new Paint (); mPaint.setColor (Color.RED); mPaint.setStyle (Paint.Style.FILL); } @Override public void getItemOffsets (Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { switch (mOrientation){ case LinearLayoutManager.HORIZONTAL: outRect.right += mSize; break; case LinearLayoutManager.VERTICAL: outRect.bottom += mSize; break; } } @Override public void onDraw (Canvas c, RecyclerView parent, RecyclerView.State state) { int left, right, top, bottom; if (mOrientation == LinearLayoutManager.VERTICAL) { left = parent.getPaddingLeft (); right = parent.getWidth () + parent.getPaddingRight (); int count = parent.getChildCount (); for (int i = 0; i < count; i++) { View child = parent.getChildAt (i); RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams (); top = child.getBottom () + params.bottomMargin; bottom = top + mSize; mDivider.setBounds (left, top, right, bottom); mDivider.draw (c); } } } @Override public void onDrawOver (Canvas c, RecyclerView parent, RecyclerView.State state) { int left, top; if (mOrientation == LinearLayoutManager.VERTICAL) { int childCount = parent.getChildCount (); for (int i = 0; i < childCount; i++) { View child = parent.getChildAt (i); left = child.getWidth () - bitmap.getWidth () - 15; top = child.getBottom () / 2 + (child.getBottom () / 2 * i) / (i + 1) - bitmap.getHeight () / 2; c.drawBitmap (bitmap, left, top, mPaint); }}}}Copy the code

Here is the implementation of your own test

It feels perfect, and the position of the “exceptions” TAB on the right can be adjusted computationally. When I was groping to write this MyItemDecoration, I met a problem and recorded it. In the future, no matter study or work, try as much as possible to extend the scope of knowledge. Question: Rewriting onDraw method can also achieve the effect of dividing lines, so what is the function of getItemOffsets? I feel like I got a bit lucky when I ran into this problem, because I gave each Item a border, and if I didn’t have that border, I might have assumed that just overwriting onDraw was the right thing to do, because it did “look” the right way. This is what happens when you just override the onDraw method

I have the separator effect, but the border “crosses” the separator and connects to the next Item, so I rewrite the getItemOffsets method again and the effect is normal, as shown below

But why does it “cross” the dividing line? After running my own tests against the code many times, I found that the starting position of the first dividing line was calculated like this

public void onDraw (Canvas c, RecyclerView parent, RecyclerView.State state) { ...... for (int i = 0; i < childCount; i++) { View child = parent.getChildAt (i); top = child.getBottom () + params.bottomMargin; bottom = top + mSize; . }Copy the code

Get item1.getBottom () as the top of the first divider, then make top plus the set height mSize as the bottom of the first divider, and the rest of the divider and so on

Although the effect of dividing lines was drawn by onDraw method, because the getItemOffsets() method was not rewritten, each Item of RecyclerView was still set according to the original layout position. Item(x) top (x=2,3,4…) Thus, starting from Item2, the top of each Item loses an mSize of height, which also explains why the border “crosses” the dividing line