From e6ed069b326ab42b31c316b594277566d05b7bbc Mon Sep 17 00:00:00 2001 From: Michael Goderbauer Date: Wed, 6 Feb 2019 14:39:51 -0800 Subject: [PATCH] Fix initial scroll of TabBar in release mode (#27568) --- packages/flutter/lib/src/material/tabs.dart | 13 +++- packages/flutter/test/material/tabs_test.dart | 61 +++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/material/tabs.dart b/packages/flutter/lib/src/material/tabs.dart index a687324cc86..affb0a045d6 100644 --- a/packages/flutter/lib/src/material/tabs.dart +++ b/packages/flutter/lib/src/material/tabs.dart @@ -476,10 +476,21 @@ class _TabBarScrollPosition extends ScrollPositionWithSingleContext { final _TabBarState tabBar; + bool _initialViewportDimensionWasZero; + @override bool applyContentDimensions(double minScrollExtent, double maxScrollExtent) { bool result = true; - if (pixels == null) { + if (_initialViewportDimensionWasZero != true) { + // If the viewport never had a non-zero dimension, we just want to jump + // to the initial scroll position to avoid strange scrolling effects in + // release mode: In release mode, the viewport temporarily may have a + // dimension of zero before the actual dimension is calculated. In that + // scenario, setting the actual dimension would cause a strange scroll + // effect without this guard because the super call below would starts a + // ballistic scroll activity. + assert(viewportDimension != null); + _initialViewportDimensionWasZero = viewportDimension != 0.0; correctPixels(tabBar._initialScrollOffset(viewportDimension, minScrollExtent, maxScrollExtent)); result = false; } diff --git a/packages/flutter/test/material/tabs_test.dart b/packages/flutter/test/material/tabs_test.dart index 3d81d1b343b..02063e00606 100644 --- a/packages/flutter/test/material/tabs_test.dart +++ b/packages/flutter/test/material/tabs_test.dart @@ -2038,4 +2038,65 @@ void main() { expect(find.text(AlwaysKeepAliveWidget.text, skipOffstage: false), findsOneWidget); expect(find.text('4'), findsOneWidget); }); + + testWidgets('tabbar does not scroll when viewport dimensions initially change from zero to non-zero', (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/10531. + + const List tabs = [ + Tab(text: 'NEW MEXICO'), + Tab(text: 'GABBA'), + Tab(text: 'HEY'), + ]; + final TabController controller = TabController(vsync: const TestVSync(), length: tabs.length); + + Widget buildTestWidget({double width, double height}) { + return MaterialApp( + home: Center( + child: SizedBox( + height: height, + width: width, + child: Scaffold( + appBar: AppBar( + title: const Text('AppBarBug'), + bottom: PreferredSize( + preferredSize: const Size.fromHeight(30.0), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 15.0), + child: Align( + alignment: FractionalOffset.center, + child: TabBar( + controller: controller, + isScrollable: true, + tabs: tabs, + ), + ), + ), + ), + ), + body: const Center( + child: Text('Hello World'), + ), + ), + ), + ), + ); + } + + await tester.pumpWidget( + buildTestWidget( + width: 0.0, + height: 0.0, + ), + ); + + await tester.pumpWidget( + buildTestWidget( + width: 300.0, + height: 400.0, + ), + ); + + expect(tester.hasRunningAnimations, isFalse); + expect(await tester.pumpAndSettle(), 1); // no more frames are scheduled. + }); }