美文网首页Flutter
flutter: TabBarView 使用记录

flutter: TabBarView 使用记录

作者: 李小轰 | 来源:发表于2021-07-28 14:59 被阅读0次
    引言

    最近在项目里使用TabBarView实现 tab 分页的效果,今天抽空来记录一下实现过程。

    闲话不多说,直接上代码:

    class TabHomePage extends StatefulWidget {
      const TabHomePage({Key key}) : super(key: key);
    
      @override
      _TabHomePageState createState() => _TabHomePageState();
    }
    
    class _TabHomePageState extends State<TabHomePage>
        with SingleTickerProviderStateMixin {
      List tabs = ["分类1", "分类2", "分类3", "分类4"];
      TabController _controller;
    
      @override
      void initState() {
        super.initState();
        _controller = TabController(
          length: tabs.length,
          vsync: this,
        );
      }
    
      @override
      void dispose() {
        super.dispose();
        _controller.dispose();
      }
    
      Widget _tabBar() {
        return Container(
          height: 56,
          color: Colors.white,
          child: TabBar(
              controller: _controller,
              labelStyle: TextStyle(
                fontSize: 14,
                fontWeight: FontWeight.bold,
              ),
              labelColor: Colors.green,
              unselectedLabelColor: Colors.black26,
              indicator: CustomUnderlineTabIndicator(
                  wantWidth: 36,
                  insets: EdgeInsets.only(
                    left: 15,
                    right: 15,
                  ),
                  borderSide: BorderSide(
                    width: 4,
                    color: Colors.green,
                  )),
              tabs: tabs
                  .map((e) => Tab(
                        text: e,
                      ))
                  .toList()),
        );
      }
    
      Widget _body() {
        return TabBarView(
          controller: _controller,
          children: tabs.map((item) {
            return Container(
              child: Center(
                child: Text(item),
              ),
            );
          }).toList(),
        );
      }
    
      @override
      Widget build(BuildContext context) {
        return Material(
          child: Container(
            child: Column(
              children: [
                _tabBar(),
                Expanded(
                  child: _body(),
                ),
              ],
            ),
          ),
        );
      }
    }
    

    CustomUnderlineTabIndicator 为自定义圆角游标,代码文末附上。

    实现效果如下:
    实现效果
    附注, 每次切换Tab,子view都会重新走init初始化,处理方案如下:
    • 子页面的 widgetState 继承 AutomaticKeepAliveClientMixin
    • 重写方法
     @override
      bool get wantKeepAlive => true;
    
    • build 方法实现父方法 super.build(context);

    自定义圆角游标代码
    import 'package:flutter/material.dart';
    
    ///参考UnderlineTabIndicator,仅仅修改画笔StrokeCap.square 为 StrokeCap.round
    // ignore: must_be_immutable
    class CustomUnderlineTabIndicator extends Decoration {
      double wantWidth;
    
      /// Create an underline style selected tab indicator.
      ///
      /// The [borderSide] and [insets] arguments must not be null.
      CustomUnderlineTabIndicator({
        this.borderSide = const BorderSide(width: 2.0, color: Colors.white),
        this.insets = EdgeInsets.zero,
        this.wantWidth = -1,
      })  : assert(borderSide != null),
            assert(insets != null);
    
      /// The color and weight of the horizontal line drawn below the selected tab.
      final BorderSide borderSide;
    
      /// Locates the selected tab's underline relative to the tab's boundary.
      ///
      /// The [TabBar.indicatorSize] property can be used to define the tab
      /// indicator's bounds in terms of its (centered) tab widget with
      /// [TabBarIndicatorSize.label], or the entire tab with
      /// [TabBarIndicatorSize.tab].
      final EdgeInsetsGeometry insets;
    
      @override
      Decoration lerpFrom(Decoration a, double t) {
        if (a is UnderlineTabIndicator) {
          return UnderlineTabIndicator(
            borderSide: BorderSide.lerp(a.borderSide, borderSide, t),
            insets: EdgeInsetsGeometry.lerp(a.insets, insets, t),
          );
        }
        return super.lerpFrom(a, t);
      }
    
      @override
      Decoration lerpTo(Decoration b, double t) {
        if (b is UnderlineTabIndicator) {
          return UnderlineTabIndicator(
            borderSide: BorderSide.lerp(borderSide, b.borderSide, t),
            insets: EdgeInsetsGeometry.lerp(insets, b.insets, t),
          );
        }
        return super.lerpTo(b, t);
      }
    
      @override
      _UnderlinePainter createBoxPainter([VoidCallback onChanged]) {
        return _UnderlinePainter(this, onChanged);
      }
    
      Rect _indicatorRectFor(Rect rect, TextDirection textDirection) {
        assert(rect != null);
        assert(textDirection != null);
        final Rect indicator = insets.resolve(textDirection).deflateRect(rect);
        //取中间坐标
        double cw = (indicator.left + indicator.right) / 2;
        return Rect.fromLTWH(
          wantWidth != -1 ? cw - wantWidth / 2 : indicator.left,
          indicator.bottom - borderSide.width,
          wantWidth != -1 ? wantWidth : indicator.width,
          borderSide.width,
        );
      }
    
      @override
      Path getClipPath(Rect rect, TextDirection textDirection) {
        return Path()..addRect(_indicatorRectFor(rect, textDirection));
      }
    }
    
    class _UnderlinePainter extends BoxPainter {
      _UnderlinePainter(this.decoration, VoidCallback onChanged)
          : assert(decoration != null),
            super(onChanged);
    
      final CustomUnderlineTabIndicator decoration;
    
      BorderSide get borderSide => decoration.borderSide;
    
      EdgeInsetsGeometry get insets => decoration.insets;
    
      @override
      void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) {
        assert(configuration != null);
        assert(configuration.size != null);
        final Rect rect = offset & configuration.size;
        final TextDirection textDirection = configuration.textDirection;
        final Rect indicator = decoration
            ._indicatorRectFor(rect, textDirection)
            .deflate(decoration.borderSide.width / 2.0);
        final Paint paint = decoration.borderSide.toPaint();
        paint.strokeWidth = 5;
        paint.strokeCap = StrokeCap.round; //主要是修改此处  圆角
        canvas.drawLine(indicator.bottomLeft, indicator.bottomRight, paint);
      }
    }
    

    相关文章

      网友评论

        本文标题:flutter: TabBarView 使用记录

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