Use OverflowBar instead of ButtonBar in MaterialBanner (#62703)

diff --git a/packages/flutter/lib/src/material/banner.dart b/packages/flutter/lib/src/material/banner.dart
index fdbc6c9..ab6babd 100644
--- a/packages/flutter/lib/src/material/banner.dart
+++ b/packages/flutter/lib/src/material/banner.dart
@@ -7,8 +7,6 @@
 import 'package:flutter/widgets.dart';
 
 import 'banner_theme.dart';
-import 'button_bar.dart';
-import 'button_theme.dart';
 import 'divider.dart';
 import 'theme.dart';
 
@@ -66,9 +64,6 @@
   /// the [MaterialBanner].
   ///
   /// Typically this is a list of [TextButton] widgets.
-  ///
-  /// These widgets will be wrapped in a [ButtonBar], which introduces 8 pixels
-  /// of padding on each side.
   final List<Widget> actions;
 
   /// The (optional) leading widget of the [MaterialBanner].
@@ -120,9 +115,14 @@
         ?? bannerTheme.leadingPadding
         ?? const EdgeInsetsDirectional.only(end: 16.0);
 
-    final Widget buttonBar = ButtonBar(
-      layoutBehavior: ButtonBarLayoutBehavior.constrained,
-      children: actions,
+    final Widget buttonBar = Container(
+      alignment: AlignmentDirectional.centerEnd,
+      constraints: const BoxConstraints(minHeight: 52.0),
+      padding: const EdgeInsets.symmetric(horizontal: 8),
+      child: OverflowBar(
+        spacing: 8,
+        children: actions,
+      ),
     );
 
     final Color backgroundColor = this.backgroundColor
diff --git a/packages/flutter/test/material/banner_test.dart b/packages/flutter/test/material/banner_test.dart
index 9a65246..52db15a 100644
--- a/packages/flutter/test/material/banner_test.dart
+++ b/packages/flutter/test/material/banner_test.dart
@@ -74,9 +74,9 @@
     );
 
     final Offset contentBottomLeft = tester.getBottomLeft(find.text(contentText));
-    final Offset actionsTopRight = tester.getTopLeft(find.byType(ButtonBar));
-    expect(contentBottomLeft.dy, lessThan(actionsTopRight.dy));
-    expect(contentBottomLeft.dx, greaterThan(actionsTopRight.dx));
+    final Offset actionsTopLeft = tester.getTopLeft(find.byType(OverflowBar));
+    expect(contentBottomLeft.dy, lessThan(actionsTopLeft.dy));
+    expect(contentBottomLeft.dx, lessThan(actionsTopLeft.dx));
   });
 
   testWidgets('Actions laid out beside content if only one action', (WidgetTester tester) async {
@@ -97,7 +97,7 @@
     );
 
     final Offset contentBottomLeft = tester.getBottomLeft(find.text(contentText));
-    final Offset actionsTopRight = tester.getTopRight(find.byType(ButtonBar));
+    final Offset actionsTopRight = tester.getTopRight(find.byType(OverflowBar));
     expect(contentBottomLeft.dy, greaterThan(actionsTopRight.dy));
     expect(contentBottomLeft.dx, lessThan(actionsTopRight.dx));
   });
@@ -118,9 +118,9 @@
       ),
     );
 
-    final Offset actionsTopRight = tester.getTopRight(find.byType(ButtonBar));
+    final Offset actionsTopRight = tester.getTopRight(find.byType(OverflowBar));
     final Offset bannerTopRight = tester.getTopRight(find.byType(MaterialBanner));
-    expect(actionsTopRight.dx, bannerTopRight.dx);
+    expect(actionsTopRight.dx + 8, bannerTopRight.dx); // actions OverflowBar is padded by 8
   });
 
   // Regression test for https://github.com/flutter/flutter/issues/39574
@@ -142,9 +142,9 @@
       ),
     );
 
-    final Offset actionsTopLeft = tester.getTopLeft(find.byType(ButtonBar));
+    final Offset actionsTopLeft = tester.getTopLeft(find.byType(OverflowBar));
     final Offset bannerTopLeft = tester.getTopLeft(find.byType(MaterialBanner));
-    expect(actionsTopLeft.dx, bannerTopLeft.dx);
+    expect(actionsTopLeft.dx - 8, bannerTopLeft.dx); // actions OverflowBar is padded by 8
   });
 
   testWidgets('Actions laid out below content if forced override', (WidgetTester tester) async {
@@ -166,9 +166,92 @@
     );
 
     final Offset contentBottomLeft = tester.getBottomLeft(find.text(contentText));
-    final Offset actionsTopRight = tester.getTopLeft(find.byType(ButtonBar));
-    expect(contentBottomLeft.dy, lessThan(actionsTopRight.dy));
-    expect(contentBottomLeft.dx, greaterThan(actionsTopRight.dx));
+    final Offset actionsTopLeft = tester.getTopLeft(find.byType(OverflowBar));
+    expect(contentBottomLeft.dy, lessThan(actionsTopLeft.dy));
+    expect(contentBottomLeft.dx, lessThan(actionsTopLeft.dx));
+  });
+
+  testWidgets('Action widgets layout', (WidgetTester tester) async {
+    // This regression test ensures that the action widgets layout matches what
+    // it was, before ButtonBar was replaced by OverflowBar.
+
+    Widget buildFrame(int actionCount, TextDirection textDirection) {
+      return MaterialApp(
+        home: Directionality(
+          textDirection: textDirection,
+          child: MaterialBanner(
+            content: const SizedBox(width: 100, height: 100),
+            actions: List<Widget>.generate(actionCount, (int index) {
+              return SizedBox(
+                width: 64,
+                height: 48,
+                key: ValueKey<int>(index),
+              );
+            }),
+          ),
+        ),
+      );
+    }
+
+    final Finder action0 = find.byKey(const ValueKey<int>(0));
+    final Finder action1 = find.byKey(const ValueKey<int>(1));
+    final Finder action2 = find.byKey(const ValueKey<int>(2));
+
+    // The action coordinates that follow were obtained by running
+    // the test code, before ButtonBar was replaced by OverflowBar.
+
+    await tester.pumpWidget(buildFrame(1, TextDirection.ltr));
+    expect(tester.getTopLeft(action0), const Offset(728, 28));
+
+    await tester.pumpWidget(buildFrame(1, TextDirection.rtl));
+    expect(tester.getTopLeft(action0), const Offset(8, 28));
+
+    await tester.pumpWidget(buildFrame(3, TextDirection.ltr));
+    expect(tester.getTopLeft(action0), const Offset(584, 130));
+    expect(tester.getTopLeft(action1), const Offset(656, 130));
+    expect(tester.getTopLeft(action2), const Offset(728, 130));
+
+    await tester.pumpWidget(buildFrame(3, TextDirection.rtl));
+    expect(tester.getTopLeft(action0), const Offset(152, 130));
+    expect(tester.getTopLeft(action1), const Offset(80, 130));
+    expect(tester.getTopLeft(action2), const Offset(8, 130));
+  });
+
+  testWidgets('Action widgets layout with overflow', (WidgetTester tester) async {
+    // This regression test ensures that the action widgets layout matches what
+    // it was, before ButtonBar was replaced by OverflowBar.
+
+    const int actionCount = 4;
+    Widget buildFrame(TextDirection textDirection) {
+      return MaterialApp(
+        home: Directionality(
+          textDirection: textDirection,
+          child: MaterialBanner(
+            content: const SizedBox(width: 100, height: 100),
+            actions: List<Widget>.generate(actionCount, (int index) {
+              return SizedBox(
+                width: 200,
+                height: 10,
+                key: ValueKey<int>(index),
+              );
+            }),
+          ),
+        ),
+      );
+    }
+
+    // The action coordinates that follow were obtained by running
+    // the test code, before ButtonBar was replaced by OverflowBar.
+
+    await tester.pumpWidget(buildFrame(TextDirection.ltr));
+    for (int index = 0; index < actionCount; index += 1) {
+      expect(tester.getTopLeft(find.byKey(ValueKey<int>(index))), Offset(8, 134.0 + index * 10));
+    }
+
+    await tester.pumpWidget(buildFrame(TextDirection.rtl));
+    for (int index = 0; index < actionCount; index += 1) {
+      expect(tester.getTopLeft(find.byKey(ValueKey<int>(index))), Offset(592, 134.0 + index * 10));
+    }
   });
 }