The latest update Flutter Tab is nested to slide like silk

TabBar and TabBarView are used in Flutter. If it is a level 2 TabBar, the product has a requirement: The level 2 TabBar should be linked, that is, the TabBar of the lower layer cannot move, so you slide the TabBar of the upper layer. I don’t know what this effect is called in Android /IOS, but I did not find it on the Internet.

QQ group: 181398081

directory

  • Tandem TabBarView

  • ColorTabIndicator

  • Controls the number of pages cached CacheExtent

Tandem TabBarView

So we open up flutter\packages\flutter\lib\ SRC \material\tabs. Dart and start the magic change.

1. First we need to get the TabBarView of the upper layer.

 Widget build(BuildContext context) {
    if (widget.linkWithAncestor) {
      _ancestor =
          context.ancestorStateOfType(TypeMatcher<_ExtendedTabBarViewState>());
    }
Copy the code
  1. We can get the OverscrollNotification if we can’t swipe, so before we look at that, it’s highly recommended to look at a NotificationListener, which is a good thing, because it listens for all kinds of notifications.

We’re going to go to the _handleScrollNotification method and add the judgment notification is OverscrollNotification

    if (notification isOverscrollNotification && _ancestor ! =null) {
      var overscrollNotification = notification as OverscrollNotification;
      if (_canlinkeWithAncestorScroll(overscrollNotification.overscroll < 0)) { _ancestor._pageController.position.moveTo( _ancestor._pageController.offset + overscrollNotification.overscroll); }}Copy the code

And through _canlinkeWithAncestorScroll method can determine whether a layer TabBarView sliding

bool _canlinkeWithAncestorScroll(bool onLeftEdge) {
    //return false;
    if (_ancestor == null) return false;
    return(onLeftEdge && _ancestor._pageController.offset ! = _ancestor._pageController.position.minScrollExtent) || ((! onLeftEdge && _ancestor._pageController.offset ! = _ancestor._pageController.position.maxScrollExtent)); }Copy the code

3. Change the _pageController of the upper TabBarView to offset and drag the overscroll. And that’s it.

_ancestor._pageController.position.moveTo(
            _ancestor._pageController.offset +
                overscrollNotification.overscroll);
Copy the code

4. If the upper layer can slide, we need to remove the damping effect of the overscroll. The increase of OverscrollIndicatorNotification listeners in the first place

 return NotificationListener<ScrollNotification>(
      onNotification: _handleScrollNotification,
      child: NotificationListener<OverscrollIndicatorNotification>(
        onNotification: _handleGlowNotification,
        child: ExtendedPageView(
          controller: _pageController,
          physics: widget.physics == null
              ? _kTabBarViewPhysics
              : _kTabBarViewPhysics.applyTo(widget.physics),
          children: _children,
        ),
      ),
    );
Copy the code

Check whether the upper TabBarView can slide

 bool _handleGlowNotification(OverscrollIndicatorNotification notification) {
    debugPrint("${notification.depth}++++ ${_ancestor ! =null}");
    if (notification.depth == 0 &&
        _canlinkeWithAncestorScroll(notification.leading)) {
      notification.disallowGlow();
      return true;
    }
    return false;
  }
Copy the code

The e linkage effect of the product is done. Isn’t it easy… Read the source code or there are many benefits.

ColorTabIndicator

This is the delivery function. ╯□╰ Is a TabBar indicator is a color block, there is nothing to say about the code

class ColorTabIndicator extends Decoration {
  ColorTabIndicator(this.color);

  /// The color and weight of the horizontal line drawn below the selected tab.
  final Color color;

  @override
  Decoration lerpFrom(Decoration a, double t) {
    return super.lerpFrom(a, t);
  }

  @override
  Decoration lerpTo(Decoration b, double t) {
    return super.lerpTo(b, t);
  }

  @override
  _ColorPainter createBoxPainter([VoidCallback onChanged]) {
    return _ColorPainter(this, onChanged); }}class _ColorPainter extends BoxPainter {
  _ColorPainter(this.decoration, VoidCallback onChanged)
      : assert(decoration ! =null),
        super(onChanged);

  final ColorTabIndicator decoration;

  @override
  void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) {
    assert(configuration ! =null);
    assert(configuration.size ! =null);
    final Rect rect = offset & configuration.size;
    finalPaint paint = Paint(); paint.color = decoration.color; canvas.drawRect(rect, paint); }}Copy the code

Controls the number of pages cached CacheExtent

  /// cache page count
  /// default is 0.
  /// if cacheExtent is 1, it has two pages in cache
  /// null is infinity, it will cache all pages
  final int cacheExtent;
Copy the code

Controls the number of pages cached by TabBarView by overriding the cacheExtent value of the Viewport in PageView.

In the build method of ExtendedPageView, a cacheExtend setting for Viewport has been added.

 child: Scrollable(
        axisDirection: axisDirection,
        controller: widget.controller,
        physics: physics,
        viewportBuilder: (BuildContext context, ViewportOffset position) {
          if (widget.cacheExtent > 0) {
            return LayoutBuilder(
                builder: (BuildContext context, BoxConstraints constraints) {
              return Viewport(
                cacheExtent: widget.cacheExtent * constraints.maxWidth,
                axisDirection: axisDirection,
                offset: position,
                slivers: <Widget>[
                  SliverFillViewport(
                      viewportFraction: widget.controller.viewportFraction,
                      delegate: widget.childrenDelegate),
                ],
              );
            });
          } else {
            return Viewport(
              cacheExtent: widget.cacheExtent == null ? double.infinity : 0.0, axisDirection: axisDirection, offset: position, slivers: <Widget>[ SliverFillViewport( viewportFraction: widget.controller.viewportFraction, delegate: widget.childrenDelegate), ], ); }}),Copy the code

Finally put Github Extended_tabs and let me know if there’s anything you don’t understand.

QQ group: 181398081