Do not animate `TabBarView` if controller is invalid (#123442)
diff --git a/packages/flutter/lib/src/material/tabs.dart b/packages/flutter/lib/src/material/tabs.dart
index 9686d1c..e2dd48a 100644
--- a/packages/flutter/lib/src/material/tabs.dart
+++ b/packages/flutter/lib/src/material/tabs.dart
@@ -1893,6 +1893,10 @@
return false;
}
+ if (!_controllerIsValid) {
+ return false;
+ }
+
_scrollUnderwayCount += 1;
if (notification is ScrollUpdateNotification && !_controller!.indexIsChanging) {
final bool pageChanged = (_pageController.page! - _controller!.index).abs() > 1.0;
diff --git a/packages/flutter/test/material/tabs_test.dart b/packages/flutter/test/material/tabs_test.dart
index 5072a74..7a9e851 100644
--- a/packages/flutter/test/material/tabs_test.dart
+++ b/packages/flutter/test/material/tabs_test.dart
@@ -3818,6 +3818,68 @@
));
});
+ testWidgets('TabController changes while flinging', (WidgetTester tester) async {
+ // This is a regression test for https://github.com/flutter/flutter/issues/34744
+
+ Widget buildFrame(TabController controller) {
+
+ return MaterialApp(
+ theme: ThemeData(platform: TargetPlatform.iOS),
+ home: Scaffold(
+ appBar: AppBar(
+ title: const Text('tabs'),
+ bottom: TabBar(
+ controller: controller,
+ tabs: <Tab>[
+ const Tab(text: 'A'),
+ const Tab(text: 'B'),
+ if (controller.length == 3)
+ const Tab(text: 'C'),
+ ],
+ ),
+ ),
+ body: TabBarView(
+ controller: controller,
+ children: <Widget>[
+ const Center(child: Text('CHILD A')),
+ const Center(child: Text('CHILD B')),
+ if (controller.length == 3)
+ const Center(child: Text('CHILD C')),
+ ],
+ ),
+ ),
+ );
+ }
+
+ final TabController controller1 = TabController(
+ vsync: const TestVSync(),
+ length: 2,
+ );
+
+ final TabController controller2 = TabController(
+ vsync: const TestVSync(),
+ length: 3,
+ );
+
+ expect(controller1.index, 0);
+ expect(controller2.index, 0);
+
+ await tester.pumpWidget(buildFrame(controller1));
+ final Offset flingStart = tester.getCenter(find.text('CHILD A'));
+ await tester.flingFrom(flingStart, const Offset(-200.0, 0.0), 10000.0);
+ await tester.pump(const Duration(milliseconds: 10)); // start the fling animation
+
+ controller1.dispose();
+ await tester.pump(const Duration(milliseconds: 10));
+
+ await tester.pumpWidget(buildFrame(controller2)); // replace controller
+ await tester.flingFrom(flingStart, const Offset(-200.0, 0.0), 10000.0);
+ await tester.pumpAndSettle(); // finish the fling animation
+
+ expect(controller1.index, 0);
+ expect(controller2.index, 1);
+ });
+
testWidgets('TabController changes with different initialIndex', (WidgetTester tester) async {
// This is a regression test for https://github.com/flutter/flutter/issues/115917
const Key lastTabKey = Key('Last Tab');