Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do not animate TabBarView if controller is invalid #123442

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/flutter/lib/src/material/tabs.dart
Expand Up @@ -1893,6 +1893,10 @@ class _TabBarViewState extends State<TabBarView> {
return false;
}

if (!_controllerIsValid) {
return false;
}

_scrollUnderwayCount += 1;
if (notification is ScrollUpdateNotification && !_controller!.indexIsChanging) {
final bool pageChanged = (_pageController.page! - _controller!.index).abs() > 1.0;
Expand Down
62 changes: 62 additions & 0 deletions packages/flutter/test/material/tabs_test.dart
Expand Up @@ -3818,6 +3818,68 @@ void main() {
));
});

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');
Expand Down