Added Badge.isLabelVisible flag (#115292)

diff --git a/packages/flutter/lib/src/material/badge.dart b/packages/flutter/lib/src/material/badge.dart
index 1cb3d68..e4fd4c2 100644
--- a/packages/flutter/lib/src/material/badge.dart
+++ b/packages/flutter/lib/src/material/badge.dart
@@ -36,6 +36,7 @@
     this.padding,
     this.alignment,
     this.label,
+    this.isLabelVisible = true,
     this.child,
   });
 
@@ -102,6 +103,12 @@
   /// this is a [StadiumBorder] shaped "large" badge with height [largeSize].
   final Widget? label;
 
+  /// If false, the badge's [label] is not included.
+  ///
+  /// This flag is true by default. It's intended to make it convenient
+  /// to create a badge that's only shown under certain conditions.
+  final bool isLabelVisible;
+
   /// The widget that the badge is stacked on top of.
   ///
   /// Typically this is an default sized [Icon] that's part of a
@@ -110,6 +117,10 @@
 
   @override
   Widget build(BuildContext context) {
+    if (!isLabelVisible) {
+      return child ?? const SizedBox();
+    }
+
     final BadgeThemeData badgeTheme = BadgeTheme.of(context);
     final BadgeThemeData defaults = _BadgeDefaultsM3(context);
     final double effectiveSmallSize = smallSize ?? badgeTheme.smallSize ?? defaults.smallSize!;
diff --git a/packages/flutter/test/material/badge_test.dart b/packages/flutter/test/material/badge_test.dart
index 6dce589..b5de837 100644
--- a/packages/flutter/test/material/badge_test.dart
+++ b/packages/flutter/test/material/badge_test.dart
@@ -20,7 +20,7 @@
           alignment: Alignment.topLeft,
           child: Builder(
             builder: (BuildContext context) {
-              // theme.textTtheme is updated when the MaterialApp is built.
+              // theme.textTheme is updated when the MaterialApp is built.
               theme = Theme.of(context);
               return const Badge(
                 label: Text('0'),
@@ -71,7 +71,7 @@
             alignment: Alignment.topLeft,
             child: Builder(
               builder: (BuildContext context) {
-                // theme.textTtheme is updated when the MaterialApp is built.
+                // theme.textTheme is updated when the MaterialApp is built.
                 theme = Theme.of(context);
                 return const Badge(
                   label: Text('0'),
@@ -202,5 +202,27 @@
     expect(tester.renderObject(find.byType(Badge)), paints..rrect(color: black));
   });
 
+  testWidgets('isLabelVisible', (WidgetTester tester) async {
+    await tester.pumpWidget(
+      MaterialApp(
+        theme: ThemeData.light(useMaterial3: true),
+        home: const Align(
+          alignment: Alignment.topLeft,
+          child: Badge(
+            label: Text('0'),
+            isLabelVisible: false,
+            child: Icon(Icons.add),
+          ),
+        ),
+      ),
+    );
 
+    expect(find.text('0'), findsNothing);
+    expect(find.byType(Icon), findsOneWidget);
+
+    expect(tester.getSize(find.byType(Badge)), const Size(24, 24)); // default Icon size
+    expect(tester.getTopLeft(find.byType(Badge)), Offset.zero);
+    final RenderBox box = tester.renderObject(find.byType(Badge));
+    expect(box, isNot(paints..rrect()));
+  });
 }