preface

In the process of doing chapter management, I found a problem. Simply providing an infinite scrolling ListView complicates things a little bit;

If you just use an infinitely scrolling ListView, the index will appear repeatedly, so that the content and index can’t be bound; If you simply decide whether the current operation is the previous page or the next page, it will feel very troublesome; So that was the case before, when you introduce jumping from the current chapter to the previous chapter or the next chapter, you’re actually doing a little bit of a mess;

Therefore, I plan to redesign the reader. The whole reader consists of a large ListView on the outside and three small listviews nested inside. These three small ListViews respectively represent the previous chapter, the next chapter and the current chapter. The ListView in the previous chapter sets the initial index to the end; Then the three small ListViews are animated the same way as the big ListView outside; Imagine, like there’s nothing wrong with that?

This brings up a problem: how to let the small ListView inside the large ListView slide, sliding will have nested slide effect;

plan

I actually thought about this a long time ago:

Create a nested slide PageView with Flutter from scratch

The solution was to refer to NestedScrollView, but there was a problem:

ListView, or any other slideable View, before the end of the animation or before begin a new activity, swipe quickly, or hold down halfway and then slide, to slide the outermost View instead of the desired inner View;

In fact, strictly speaking, the internal View does not respond to any operation; It didn’t even enter the gesture competition

, for example, in this way, you can see the middle tab000, tab001 tab01 belong to the four sub TAB just skip, operating tab00, tab01 this layer TAB:

PS: In extend_tab’s issue area there is a solution for this fast sliding case, which is to make the animation faster, so that the fast sliding operation is not as fast as the animation playback speed, which can solve this problem, adjust the sliding animation to a point that is barely acceptable: issue

In the design of this scheme, we generally refer to the previous scheme, but try to extract the core logic into mixin, and provide it in the form of processing and encapsulation like Android’s NestedScrollChild and NestedScrollParent. Also try to solve the problem mentioned above:

design

The first is the previous scheme modification:

In the previous scheme, NestedScrollView and its internal controller of sliding View are combined and assembled into a coordiantor for unified management by referring to the implementation of NestedScrollView.

This time the whole logic part is left intact. I want to put the logic in the mixin, and then the child View can communicate by looking for the mixin in the parent. After all, for a slideable View, all you need to do is get something like a controller, and you can manipulate it;

Secondly, because the above scheme is based on the call judgment of the sub-view itself to achieve, so the first problem to solve is the above mentioned, the sub-view will not feedback, even did not join the gesture competition field this problem;

Analysis of the

First of all, the source of this problem is that the gesture of the sub-view is not added to the gesture competition field, so the first thing to analyze is the process of gesture competition:

However, this problem, in fact, there are too many articles, its process can not be explained clearly in one or two sentences, so I will not repeat it here, directly focus on why it is not added to the gesture competitor:

Since the method to add gestures to the gesture competitor is the addPointer method, you can trace this method to see the shadow of RawGestureDetector.

So why doesn’t the RawGestureDetector held by the child Scrollable put gesture information into the competitor?

The answer is simple, intercepted;

In the previous ListView analysis, you can see that there is an IgnorePointer in Scrollable, and the ScrollController also calls the setIgnorePointer method to set whether to intercept, Many activities will set this value to true to intercept the child View’s gesture event; Setting this value to false gives the child View the advantage of the gesture event and gives it priority;

For example, the extend_tab project, shown in the demo above, solves the problem of fast sliding by simply not intercepting:

ShouldIgnorePointer = shouldIgnorePointer;

If you look at the effect now, you can see that the slider animation of the indicator above does not affect the child tabs to handle gestures even though it is not finished:

So is there no problem now? Definitely not, for example, in the middle of the slide, release the immediate press and slide again, because the external TAB lost to the child TAB in the competitor, triggering the cancel reset, so even without releasing the gesture, the external TAB still slides (you can see that the mouse has been holding down) :

So whether to intercept this piece, it is necessary to make a comprehensive judgment based on logic; You can’t simply set false to complete the task;