custom_tab_indicator.dart 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. import 'package:flutter/material.dart';
  2. /// 自定义Tab的指示器
  3. class CustomTabIndicator extends Decoration {
  4. /// Create an underline style selected tab indicator.
  5. ///
  6. /// The [borderSide] and [insets] arguments must not be null.
  7. const CustomTabIndicator({
  8. this.width = 20,
  9. this.strokeCap = StrokeCap.round,
  10. this.borderSide = const BorderSide(width: 2.0, color: Colors.white),
  11. this.insets = EdgeInsets.zero,
  12. });
  13. /// The color and weight of the horizontal line drawn below the selected tab.
  14. final BorderSide borderSide;
  15. /// Locates the selected tab's underline relative to the tab's boundary.
  16. ///
  17. /// The [TabBar.indicatorSize] property can be used to define the tab
  18. /// indicator's bounds in terms of its (centered) tab widget with
  19. /// [TabBarIndicatorSize.label], or the entire tab with
  20. /// [TabBarIndicatorSize.tab].
  21. final EdgeInsetsGeometry insets;
  22. /// 新增属性:控制器宽度
  23. final double width;
  24. /// 新增属性:控制器边角形状
  25. final StrokeCap strokeCap;
  26. @override
  27. Decoration? lerpFrom(Decoration? a, double t) {
  28. if (a is CustomTabIndicator) {
  29. return CustomTabIndicator(
  30. borderSide: BorderSide.lerp(a.borderSide, borderSide, t),
  31. insets: EdgeInsetsGeometry.lerp(a.insets, insets, t)!,
  32. );
  33. }
  34. return super.lerpFrom(a, t);
  35. }
  36. @override
  37. Decoration? lerpTo(Decoration? b, double t) {
  38. if (b is CustomTabIndicator) {
  39. return CustomTabIndicator(
  40. borderSide: BorderSide.lerp(borderSide, b.borderSide, t),
  41. insets: EdgeInsetsGeometry.lerp(insets, b.insets, t)!,
  42. );
  43. }
  44. return super.lerpTo(b, t);
  45. }
  46. @override
  47. BoxPainter createBoxPainter([VoidCallback? onChanged]) {
  48. return _UnderlinePainter(this, onChanged);
  49. }
  50. /// 决定控制器宽度的方法
  51. Rect _indicatorRectFor(Rect rect, TextDirection textDirection) {
  52. final Rect indicator = insets.resolve(textDirection).deflateRect(rect);
  53. // 希望的宽度
  54. double wantWidth = width;
  55. // 取中间坐标
  56. double cw = (indicator.left + indicator.right) / 2;
  57. // 下划线靠左
  58. // return Rect.fromLTWH(indicator.left,
  59. // indicator.bottom - borderSide.width, wantWidth, borderSide.width);
  60. //下划线居中
  61. return Rect.fromLTWH(
  62. cw - wantWidth / 2,
  63. indicator.bottom - borderSide.width,
  64. wantWidth,
  65. borderSide.width,
  66. );
  67. }
  68. @override
  69. Path getClipPath(Rect rect, TextDirection textDirection) {
  70. return Path()..addRect(_indicatorRectFor(rect, textDirection));
  71. }
  72. }
  73. class _UnderlinePainter extends BoxPainter {
  74. _UnderlinePainter(this.decoration, VoidCallback? onChanged)
  75. : super(onChanged);
  76. final CustomTabIndicator decoration;
  77. /// 决定控制器边角形状的方法
  78. @override
  79. void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) {
  80. assert(configuration.size != null);
  81. final Rect rect = offset & configuration.size!;
  82. final TextDirection textDirection = configuration.textDirection!;
  83. final Rect indicator = decoration
  84. ._indicatorRectFor(rect, textDirection)
  85. .deflate(decoration.borderSide.width / 2.0);
  86. final Paint paint =
  87. decoration.borderSide.toPaint()..strokeCap = decoration.strokeCap;
  88. canvas.drawLine(indicator.bottomLeft, indicator.bottomRight, paint);
  89. }
  90. }