Flutter 自定义TabBar的指示器indicator<转载>

  • Post author:
  • Post category:其他


Flutter 自定义TabBar的指示器indicator<转载>

转载地址:

https://www.jianshu.com/p/878fd1cf7ca9

使用:

TabBar(
            controller: _tabController,  // tab 控制器
            isScrollable: true,  // tab 是否可以滑动
            automaticIndicatorColorAdjustment: false, //是否应该自动调整[indicatorColor]。 当为true,会自动调整为白色
            labelColor: Colors.red,  // label 选中文字的颜色
            unselectedLabelColor: Colors.grey, // label 未选中文字的颜色
            indicatorSize: TabBarIndicatorSize.label,  //indicator 大小,TabBarIndicatorSize.label,TabBarIndicatorSize.tab
            indicator: const CustomTabIndicator(
                width: 20,
                borderSide: BorderSide(width: 2.0, color: Colors.red)),
           indicatorColor: Colors.blue, // 设置indicator 颜色,当我们设置了indicator 属性之后,该属性设置将会失败,以indicator中设置的颜色为准
            tabs: List.generate(
                tabBarItemList.length,
                (index) => Tab(
                      text: tabBarItemList[index],
                    )))

Widget:

import 'package:flutter/material.dart';

class CustomTabIndicator extends Decoration {
  /// Create an underline style selected tab indicator.
  ///
  /// The [borderSide] and [insets] arguments must not be null.
  const CustomTabIndicator({
    this.width = 20,
    this.strokeCap = StrokeCap.round,
    this.borderSide = const BorderSide(width: 2.0, color: Colors.white),
    this.insets = EdgeInsets.zero,
  })  : 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;

  ///新增的属性
  final double width; // 控制器宽度
  final StrokeCap strokeCap; // 控制器边角形状

  @override
  Decoration? lerpFrom(Decoration? a, double t) {
    if (a is CustomTabIndicator) {
      return CustomTabIndicator(
        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 CustomTabIndicator) {
      return CustomTabIndicator(
        borderSide: BorderSide.lerp(borderSide, b.borderSide, t),
        insets: EdgeInsetsGeometry.lerp(insets, b.insets, t)!,
      );
    }
    return super.lerpTo(b, t);
  }

  @override
  BoxPainter 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 wantWidth = this.width;
    // 取中间坐标
    double cw = (indicator.left + indicator.right) / 2;

    print(
        '$cw,indicator left${indicator.left}, right ${indicator.right}, indicator top ${indicator.top},indicator bottom${indicator.bottom}, border width${borderSide.width}');
  //这里是核心代码 //下划线靠左
    // return Rect.fromLTWH(indicator.left,
    //     indicator.bottom - borderSide.width, wantWidth, borderSide.width);

    //下划线居中
    return Rect.fromLTWH(cw - wantWidth / 2,
        indicator.bottom - borderSide.width, wantWidth, 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 CustomTabIndicator decoration;

  ///决定控制器边角形状的方法
  @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()
      ..strokeCap = decoration.strokeCap; //这块更改为想要的形状
    canvas.drawLine(indicator.bottomLeft, indicator.bottomRight, paint);
  }
}

转载于 :

https://www.jianshu.com/p/878fd1cf7ca9