This article will introduce a very practical Flutter list sliding knowledge point through a demand scenario. The problem comes from the netizens’ consultation.
Create a chat list on Flutter. This is a ListView that displays the render data by type. What’s so hard about that?
There is nothing wrong in theory, but there is one requirement scenario where there is an unfixable problem: chat lists require two-way insertion of data.
What problems can be caused by bidirectional insertion of data in the ListView? For example, first we draw a simulated chat list using the common ListView. Here we use reverse to reverse the list to meet the UI requirements, and let the list slide from the bottom of the web:
ListView.builder(
controller: scroller,
reverse: true,
itemBuilder: (context, index) {
var item = data[index];
if (item.type == "Right")
return renderRightItem(item);
else
return renderLeftItem(item);
},
itemCount: data.length,
)
Copy the code
After running, the effect is shown as follows:
- First add red to simulate loading old data
list.add
, you can see that the above data appears, no problem; - And then we slide a little bit, no problem;
- Green data is then added to simulate the receipt of new messages
list.insert
.You can see that the list jumps and doesn’t stay where we were before; - We continue to slide, simulating the receipt of new messages, and the list continues to jump;
Any questions? If the effect product is acceptable, then no problem. But if the product holds the QQ chat and asks you, why does the list not jump when others receive new messages? This problem not come ~
First of all, why does the list jump? As discussed in Different Perspectives on the implementation of Flutter, the slide list effect of Flutter mainly consists of three parts:
Viewport
: It provides the function of a “window”, i.e. the size of the viewable area in which the list is located;Scrollable
: It mainly through the gesture processing to achieve sliding effect;Sliver
: ExactlyRenderSliver
It is mainly used inViewport
Layout and render content inside, for exampleSliverList
;
If this all seems too abstract, combine this with the following:
- green
Viewport
That’s the size of the list window that we saw; - The purple is for gestures
Scrollable
Let the yellow partSliverList
在Viewport
To produce sliding; - The yellow part is
SliverList
When we slide, it’s actually changing its position in Viewport;
Everything was fine, but when we added the green part of the insert, the data in the insert header (the green part) pushed the original SliverList back up, resulting in a change in the SliverList position.
So essentially the SliverList gets longer, the starting point changes, and the position in the Viewport changes.
So how to solve this problem? Ll: Well, why don’t we just let him jump back to his original position?
As shown in the figure below, we record the original location, then add data, then get the size of the added data, then jump to the original location, the effect is flashing ~
So how to solve this problem? This relates to a key point of Flutter list sliding: center.
What is the center of a list?
So center is a key parameter in ViewPort, and the default is the first RenderSliver, which determines where scrollOffset = 0.
In addition, center is a Key object, which means that in addition to the default, we can specify the location of center by Key.
In other words, if we insert the old data before center, and the new data after center, wouldn’t the list see any slippage?
So how do we configure Center? This is where CustomScrollView is used, CustomScrollView supports configuration Center, and CustomScrollView directly configures the slivers array you need.
That is, instead of having a single SliverList like a ListView, we can configure two SliverLists and put a center in the middle.
As shown in the code below, because of the chat list scenario, our list is reverse, so we need to put the new data’s SliverList above the centerKey and the old data’s SliverList below the centerKey.
CustomScrollView(
controller: scroller,
reverse: true,
center: centerKey,
slivers: [
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
var item = newData[index];
if (item.type == "Right")
return renderRightItem(item);
else
return renderLeftItem(item);
},
childCount: newData.length,
),
),
SliverPadding(
padding: EdgeInsets.zero,
key: centerKey,
),
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
var item = loadMoreData[index];
if (item.type == "Right")
return renderRightItem(item);
else
return renderLeftItem(item);
},
childCount: loadMoreData.length,
),
),
],
)
Copy the code
After running, the effect is shown in the figure. It can be seen that even when the green data is added, the list does not jump. In fact, the sliding effect of the layout now is changed from the original sliding range of 0 ~ XXX to the sliding range of -AAA ~ BB.
We said that center determines the position of scrollOffset = 0, so when we do this, we have a range from 0 to ♾️ and from -♾️ to 0, so when we insert data into the header, It inserts data in the direction of minScrollExtent, adding a negative Offset so that the list does not shift.
Although the implementation of Flutter is simple, it is easy to get bogged down in ListvView without understanding the sliding list mechanism of Flutter. This article is also intended to open up your mind and improve your understanding of ViewPort and Sliver.
If you have any questions or thoughts about Flutter, feel free to leave a comment.