Skip to content

Commit e9622ce

Browse files
authored
Added Badge.count constructor (#115297)
1 parent e8cbd44 commit e9622ce

File tree

2 files changed

+75
-0
lines changed

2 files changed

+75
-0
lines changed

packages/flutter/lib/src/material/badge.dart

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,24 @@ class Badge extends StatelessWidget {
4040
this.child,
4141
});
4242

43+
/// Convenience constructor for creating a badge with a numeric
44+
/// label with 1-3 digits based on [count].
45+
///
46+
/// Initializes [label] with a [Text] widget that contains [count].
47+
/// If [count] is greater than 999, then the label is '999+'.
48+
Badge.count({
49+
super.key,
50+
this.backgroundColor,
51+
this.textColor,
52+
this.smallSize,
53+
this.largeSize,
54+
this.textStyle,
55+
this.padding,
56+
this.alignment,
57+
required int count,
58+
this.child,
59+
}) : label = Text(count > 999 ? '999+' : '$count');
60+
4361
/// The badge's fill color.
4462
///
4563
/// Defaults to the [BadgeTheme]'s background color, or

packages/flutter/test/material/badge_test.dart

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,63 @@ void main() {
111111
expect(box, paints..rrect(rrect: RRect.fromLTRBR(-8, -4, 12, 12, const Radius.circular(8)), color: theme.colorScheme.error));
112112
});
113113

114+
// Essentially the same as 'Large Badge defaults'
115+
testWidgets('Badge.count', (WidgetTester tester) async {
116+
late final ThemeData theme;
117+
118+
Widget buildFrame(int count) {
119+
return MaterialApp(
120+
theme: ThemeData.light(useMaterial3: true),
121+
home: Align(
122+
alignment: Alignment.topLeft,
123+
child: Builder(
124+
builder: (BuildContext context) {
125+
// theme.textTheme is updated when the MaterialApp is built.
126+
if (count == 0) {
127+
theme = Theme.of(context);
128+
}
129+
return Badge.count(
130+
count: count,
131+
child: const Icon(Icons.add),
132+
);
133+
},
134+
),
135+
),
136+
);
137+
}
138+
139+
await tester.pumpWidget(buildFrame(0));
140+
141+
expect(
142+
tester.renderObject<RenderParagraph>(find.text('0')).text.style,
143+
theme.textTheme.labelSmall!.copyWith(color: theme.colorScheme.onError),
144+
);
145+
146+
// default badge alignment = AlignmentDirectional(12, -4)
147+
// default padding = EdgeInsets.symmetric(horizontal: 4)
148+
// default largeSize = 16
149+
// '0'.width = 12
150+
// icon.width = 24
151+
152+
expect(tester.getSize(find.byType(Badge)), const Size(24, 24)); // default Icon size
153+
expect(tester.getTopLeft(find.byType(Badge)), Offset.zero);
154+
155+
// x = alignment.start + padding.left
156+
// y = alignment.top
157+
expect(tester.getTopLeft(find.text('0')), const Offset(16, -4));
158+
159+
final RenderBox box = tester.renderObject(find.byType(Badge));
160+
// '0'.width = 12
161+
// L = alignment.start
162+
// T = alignment.top
163+
// R = L + '0'.width + padding.width
164+
// B = T + largeSize, R = largeSize/2
165+
expect(box, paints..rrect(rrect: RRect.fromLTRBR(12, -4, 32, 12, const Radius.circular(8)), color: theme.colorScheme.error));
166+
167+
await tester.pumpWidget(buildFrame(1000));
168+
expect(find.text('999+'), findsOneWidget);
169+
});
170+
114171
testWidgets('Small Badge defaults', (WidgetTester tester) async {
115172
final ThemeData theme = ThemeData.light(useMaterial3: true);
116173

0 commit comments

Comments
 (0)