diff --git a/packages/flutter/lib/src/material/tabs.dart b/packages/flutter/lib/src/material/tabs.dart index e560d109e7e..794c266a318 100644 --- a/packages/flutter/lib/src/material/tabs.dart +++ b/packages/flutter/lib/src/material/tabs.dart @@ -704,7 +704,8 @@ class _TabBarState extends ScrollableState> implements TabBarSelect void _updateScrollBehavior() { scrollTo(scrollBehavior.updateExtents( containerExtent: config.scrollDirection == Axis.vertical ? _viewportSize.height : _viewportSize.width, - contentExtent: _tabWidths.reduce((double sum, double width) => sum + width) + contentExtent: _tabWidths.reduce((double sum, double width) => sum + width), + scrollOffset: scrollOffset )); } @@ -780,7 +781,7 @@ class _TabBarState extends ScrollableState> implements TabBarSelect ); if (config.isScrollable) { - child: new Viewport( + return new Viewport( scrollDirection: Axis.horizontal, paintOffset: scrollOffsetToPixelDelta(scrollOffset), onPaintOffsetUpdateNeeded: _handlePaintOffsetUpdateNeeded, diff --git a/packages/flutter/test/widget/tabs_test.dart b/packages/flutter/test/widget/tabs_test.dart index ed1d45d0df8..a8ded320ab3 100644 --- a/packages/flutter/test/widget/tabs_test.dart +++ b/packages/flutter/test/widget/tabs_test.dart @@ -7,12 +7,13 @@ import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:test/test.dart'; -Widget buildFrame({ List tabs, String value, bool isScrollable: false }) { +Widget buildFrame({ List tabs, String value, bool isScrollable: false, Key tabBarKey }) { return new Material( child: new TabBarSelection( value: value, values: tabs, child: new TabBar( + key: tabBarKey, labels: new Map.fromIterable(tabs, value: (String tab) => new TabLabel(text: tab)), isScrollable: isScrollable ) @@ -98,4 +99,48 @@ void main() { expect(selection.value, equals('A')); }); }); + + test('Scrollable TabBar tap centers selected tab', () { + testWidgets((WidgetTester tester) { + List tabs = ['AAAAAA', 'BBBBBB', 'CCCCCC', 'DDDDDD', 'EEEEEE', 'FFFFFF', 'GGGGGG', 'HHHHHH', 'IIIIII', 'JJJJJJ', 'KKKKKK', 'LLLLLL']; + Key tabBarKey = new Key('TabBar'); + tester.pumpWidget(buildFrame(tabs: tabs, value: 'AAAAAA', isScrollable: true, tabBarKey: tabBarKey)); + TabBarSelectionState selection = TabBarSelection.of(tester.findText('AAAAAA')); + expect(selection, isNotNull); + expect(selection.value, equals('AAAAAA')); + + expect(tester.getSize(tester.findElementByKey(tabBarKey)).width, equals(800.0)); + // The center of the FFFFFF item is to the right of the TabBar's center + expect(tester.getCenter(tester.findText('FFFFFF')).x, greaterThan(401.0)); + + tester.tap(tester.findText('FFFFFF')); + tester.pump(); + tester.pump(const Duration(seconds: 1)); // finish the scroll animation + expect(selection.value, equals('FFFFFF')); + // The center of the FFFFFF item is now at the TabBar's center + expect(tester.getCenter(tester.findText('FFFFFF')).x, closeTo(400.0, 1.0)); + }); + }); + + + test('TabBar can be scrolled independent of the selection', () { + testWidgets((WidgetTester tester) { + List tabs = ['AAAAAA', 'BBBBBB', 'CCCCCC', 'DDDDDD', 'EEEEEE', 'FFFFFF', 'GGGGGG', 'HHHHHH', 'IIIIII', 'JJJJJJ', 'KKKKKK', 'LLLLLL']; + Key tabBarKey = new Key('TabBar'); + tester.pumpWidget(buildFrame(tabs: tabs, value: 'AAAAAA', isScrollable: true, tabBarKey: tabBarKey)); + TabBarSelectionState selection = TabBarSelection.of(tester.findText('AAAAAA')); + expect(selection, isNotNull); + expect(selection.value, equals('AAAAAA')); + + // Fling-scroll the TabBar to the left + expect(tester.getCenter(tester.findText('HHHHHH')).x, lessThan(700.0)); + tester.fling(tester.findElementByKey(tabBarKey), const Offset(-20.0, 0.0), 1000.0); + tester.pump(); + tester.pump(const Duration(seconds: 1)); // finish the scroll animation + expect(tester.getCenter(tester.findText('HHHHHH')).x, lessThan(500.0)); + + // Scrolling the TabBar doesn't change the selection + expect(selection.value, equals('AAAAAA')); + }); + }); }