1// Copyright 2014 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5/// @docImport 'tabs.dart';
6library;
7
8import 'package:flutter/widgets.dart';
9
10import 'colors.dart';
11
12/// Used with [TabBar.indicator] to draw a horizontal line below the
13/// selected tab.
14///
15/// The selected tab underline is inset from the tab's boundary by [insets].
16/// The [borderSide] defines the line's color and weight.
17///
18/// The [TabBar.indicatorSize] property can be used to define the indicator's
19/// bounds in terms of its (centered) widget with [TabBarIndicatorSize.label],
20/// or the entire tab with [TabBarIndicatorSize.tab].
21class UnderlineTabIndicator extends Decoration {
22 /// Create an underline style selected tab indicator.
23 const UnderlineTabIndicator({
24 this.borderRadius,
25 this.borderSide = const BorderSide(width: 2.0, color: Colors.white),
26 this.insets = EdgeInsets.zero,
27 });
28
29 /// The radius of the indicator's corners.
30 ///
31 /// If this value is non-null, rounded rectangular tab indicator is
32 /// drawn, otherwise rectangular tab indicator is drawn.
33 final BorderRadius? borderRadius;
34
35 /// The color and weight of the horizontal line drawn below the selected tab.
36 final BorderSide borderSide;
37
38 /// Locates the selected tab's underline relative to the tab's boundary.
39 ///
40 /// The [TabBar.indicatorSize] property can be used to define the tab
41 /// indicator's bounds in terms of its (centered) tab widget with
42 /// [TabBarIndicatorSize.label], or the entire tab with
43 /// [TabBarIndicatorSize.tab].
44 final EdgeInsetsGeometry insets;
45
46 @override
47 Decoration? lerpFrom(Decoration? a, double t) {
48 if (a is UnderlineTabIndicator) {
49 return UnderlineTabIndicator(
50 borderSide: BorderSide.lerp(a.borderSide, borderSide, t),
51 insets: EdgeInsetsGeometry.lerp(a.insets, insets, t)!,
52 );
53 }
54 return super.lerpFrom(a, t);
55 }
56
57 @override
58 Decoration? lerpTo(Decoration? b, double t) {
59 if (b is UnderlineTabIndicator) {
60 return UnderlineTabIndicator(
61 borderSide: BorderSide.lerp(borderSide, b.borderSide, t),
62 insets: EdgeInsetsGeometry.lerp(insets, b.insets, t)!,
63 );
64 }
65 return super.lerpTo(b, t);
66 }
67
68 @override
69 BoxPainter createBoxPainter([ VoidCallback? onChanged ]) {
70 return _UnderlinePainter(this, borderRadius, onChanged);
71 }
72
73 Rect _indicatorRectFor(Rect rect, TextDirection textDirection) {
74 final Rect indicator = insets.resolve(textDirection).deflateRect(rect);
75 return Rect.fromLTWH(
76 indicator.left,
77 indicator.bottom - borderSide.width,
78 indicator.width,
79 borderSide.width,
80 );
81 }
82
83 @override
84 Path getClipPath(Rect rect, TextDirection textDirection) {
85 if (borderRadius != null) {
86 return Path()..addRRect(
87 borderRadius!.toRRect(_indicatorRectFor(rect, textDirection))
88 );
89 }
90 return Path()..addRect(_indicatorRectFor(rect, textDirection));
91 }
92}
93
94class _UnderlinePainter extends BoxPainter {
95 _UnderlinePainter(
96 this.decoration,
97 this.borderRadius,
98 super.onChanged,
99 );
100
101 final UnderlineTabIndicator decoration;
102 final BorderRadius? borderRadius;
103
104 @override
105 void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) {
106 assert(configuration.size != null);
107 final Rect rect = offset & configuration.size!;
108 final TextDirection textDirection = configuration.textDirection!;
109 final Paint paint;
110 if (borderRadius != null) {
111 paint = Paint()..color = decoration.borderSide.color;
112 final Rect indicator = decoration._indicatorRectFor(rect, textDirection);
113 final RRect rrect = RRect.fromRectAndCorners(
114 indicator,
115 topLeft: borderRadius!.topLeft,
116 topRight: borderRadius!.topRight,
117 bottomRight: borderRadius!.bottomRight,
118 bottomLeft: borderRadius!.bottomLeft,
119 );
120 canvas.drawRRect(rrect, paint);
121 } else {
122 paint = decoration.borderSide.toPaint()..strokeCap = StrokeCap.square;
123 final Rect indicator = decoration._indicatorRectFor(rect, textDirection)
124 .deflate(decoration.borderSide.width / 2.0);
125 canvas.drawLine(indicator.bottomLeft, indicator.bottomRight, paint);
126 }
127 }
128}
129

Provided by KDAB

Privacy Policy
Learn more about Flutter for embedded and desktop on industrialflutter.com