1. Introduction

Used on RecyclerView StaggeredGridLayoutManager layout manager is easy to implement the waterfall flow layout. Waterfall layouts are prettier and use more screen space than linear and grid layouts, but they are also more complex to implement and often have strange bugs.

We were going to focus on two notorious waterfall flow bugs. By deeply exploring the realization principle of waterfall flow layout, analyzing their formation reasons, and giving a solution to solve them elegantly.

1.1 bug1: blank top and reorder

Bug replay operation:

  1. Slide the waterfall to the bottom;
  2. Click the refresh button, calling Adapter. NotifyDataSetChanged ();
  3. Slide your finger away from the screen as you slide down the waterfall list to the top.

The bug description

When you slide to the top, the top goes blank, the waterfall flow reorders when you let go, and an animation is triggered.

In a real project, we don’t want the user to see this kind of obvious animation, or even a blank space at the top of the waterfall stream.

1.2 BUG2: Disordered spacing of waterfall flow

Bug replay operation is the same as bug1

The bug description

“1 Han Emperor heavy color…” “And” 5 temples flower yan…” The left side is not aligned. The overall waterfall flow layout has many of these spacing problems.

2. Solutions

2.1 BuG1 solution

Online solutions are as follows:

This method can solve the problem, but the performance is low. Because it empties the mLazySpanLookup and relayouts regardless of whether there is a blank situation.

My solution is that through reflection StaggeredGridLayoutManager checkForGaps (). When sliding, the layout is rearranged only when necessary.

The effect is as follows: Same operation, when sliding to the top, the white space problem is solved. But the buG2’s problems remain

2.2 BuG2 Solution

In this case, the interval between each Item of the waterfall flow is 10DP. The spacing between the two sides of the screen and Item is also 10DP. I realized this through ItemDecoration.

Solutions are as follows:

Perfect solution to the problem of spacing disorder.

3. Cause analysis of BUG2

Waterfall streams Span array

In this case, the waterfall stream has four columns. The screen is split into four spans. The subscripts for each Span are 0, 1, 2, and 3. And the distance between the left and the right is just changing according to the subscript. If the subscript is incorrect, the spacing of the ItemView will also be calculated incorrectly. For example, “1 Han Emperor heavy color…” Span should be 0, but if it becomes 1, its left and right margins are 5dp. The correct spacing should be 10DP left and 5DP right.

Observe spanIndex disorder

I print spanIndex in the getItemOffsets() and animateMove() methods, respectively

Zijiexiaozhan getItemOffsets 1 The Emperor of Han heavy color thinking tilt country, yu yu for many years can not index 1

Zijiexiaozhan animate 1 Han Emperor heavy color thinking inclined country, yu yu for many years can not index 0

We know that the correct spanIndex for “1 Emperor of The Han dynasty is 0. In getItemOffsets it is 1, which becomes the correct 0 when animating. There are two possible reasons

  1. GetItemOffsets is called before spanIndex is set, resulting in getItemOffsets not getting the correct spanIndex
  2. GetItemOffsets is called after spanIndex is set, but spanIndex is set multiple times, and for some reason getItemOffsets are not called synchronously

Analyze the fill method

We can see from the figure that setting spanIndex is called before the getItemOffsets method, so rule out the first possibility

Analyze getItemOffsets call timing

In getItemOffsets, the break points are obtained as follows

//RecyclerView.java The reason is that lP. mInsetsDirty is set to true at dispatchLayoutStep1. The getItemOffsets method is not called during the dispatchLayoutStep2 real layout phase. As a result, there is no opportunity to correct Decoration drawing. For RecyclerView animation principle, please refer toRecyclerView layout and animation principle.

The solution

The solution is obvious. Set lP. mInsetsDirty to false after checkForGaps returns true. Reflection calls RecyclerView markItemDecorInsetsDirty()

4. To summarize

RecyclerView is a very important component in Android UI framework. It’s easy to use and quick to handle. But when it comes to advanced use, it can be very tricky. Because I wrote a series of articles about advanced RecyclerView. It includes layout principle, animation principle, sliding principle, cache implementation mechanism, actual combat pit filling and so on. I believe you will receive the goods after learning.

This example has been uploaded to Github. Follow me in “Waterfall Flow” for the full tutorial.