Flutter 扩展的联动Tabs

作者: 2c3d4f7ba0d4 | 来源:发表于2019-08-20 19:33 被阅读3次

    Flutter里面使用TabBar和TabBarView的时候。如果是二级TabBar,产品说了一个需求:二级TabBar需要是那种联动的,就是说下面一层的TabBar滑不动了,就滑动上一层的TabBar,不知道这个效果在安卓/IOS里面叫什么,搜了下网上也没看到。

    目录

    联动的TabBarView

    那么我们打开flutter\packages\flutter\lib\src\material\tabs.dart,开始魔改。

    1.首先我们需要获取到上一层的TabBarView.

     Widget build(BuildContext context) {
        if (widget.linkWithAncestor) {
          _ancestor =
              context.ancestorStateOfType(TypeMatcher<_ExtendedTabBarViewState>());
        }
    
    1. 不能滑动的时候我们能拿到OverscrollNotification,看这个之前强烈建议去看一下NotificationListener,这个是个好东西,能监听各种通知。

    我们来到_handleScrollNotification这个方法添加判断 notification is OverscrollNotification

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

    并且通过_canlinkeWithAncestorScroll方法判断上一层TabBarView是否能滑动

    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));
      }
    

    3.将上层TabBarView的_pageController改变为offset+拖动overscroll的。这样效果就完成了。

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

    4.如果上层可以滑动,我们需要去掉overscroll的阻尼效果。 首先在增加对OverscrollIndicatorNotification的监听

     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,
            ),
          ),
        );
    

    判断是否上层TabBarView能否滑动

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

    产品要的联动效果就这样搞定了。。是不是很简单。。多看源码还是有很多好处的。。

    TabBar色卡指示器ColorTabIndicator

    这个是随手送的功能。。( ╯□╰ )就是TabBar指示器为一个色块,代码没啥好说的

    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;
        final Paint paint = Paint();
        paint.color = decoration.color;
        canvas.drawRect(rect, paint);
      }
    }
    

    控制缓存页数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;
    

    控制TabBarView缓存页面的个数,通过重写了PageView中的Viewport的cacheExtent值来实现。

    ExtendedPageView的build方法中,增加了对Viewport的cacheExtend的设置。

     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),
                  ],
                );
              }
            },
          ),
    

    最后放上 Github extended_tabs,如果你有什么不明白的地方,请告诉我

    原文链接:https://juejin.im/post/5c34b87ef265da61553b01a8

    最后

    漫漫开发之路,我们只是其中的一小部分……只有不断的学习、进阶,才是我们的出路!才跟得上时代的进步!

    我从事Android开发快十年了,今年年初我花两个月的时间收录整理了一套知识体系,此外,还有面试专题、架构视频,如果有想法深入的系统化的去学习的,可以关注我,加入Android进阶技术交流 (895077617 )免费获取整理版的资料
    ,我会把我收录整理的资料都送给大家,帮助大家更快的提升。

    重要的事说三遍,转发+转发+转发,让更多需要的朋友们都可以看到并且领到!

    相关文章

      网友评论

        本文标题:Flutter 扩展的联动Tabs

        本文链接:https://www.haomeiwen.com/subject/hpqmsctx.html