From 898c19d753eb787a60396d5304951f4beaa1497d Mon Sep 17 00:00:00 2001 From: najeira Date: Tue, 18 Jul 2017 08:59:43 +0900 Subject: [PATCH] add physics to TabBarView (#11150) --- packages/flutter/lib/src/material/tabs.dart | 14 +++- packages/flutter/test/material/tabs_test.dart | 66 +++++++++++++++++++ 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/material/tabs.dart b/packages/flutter/lib/src/material/tabs.dart index 796ca9ebc4..9760e9d6ef 100644 --- a/packages/flutter/lib/src/material/tabs.dart +++ b/packages/flutter/lib/src/material/tabs.dart @@ -795,6 +795,7 @@ class TabBarView extends StatefulWidget { Key key, @required this.children, this.controller, + this.physics, }) : assert(children != null), super(key: key); /// This widget's selection and animation state. @@ -806,6 +807,17 @@ class TabBarView extends StatefulWidget { /// One widget per tab. final List children; + /// How the page view should respond to user input. + /// + /// For example, determines how the page view continues to animate after the + /// user stops dragging the page view. + /// + /// The physics are modified to snap to page boundaries using + /// [PageScrollPhysics] prior to being used. + /// + /// Defaults to matching platform conventions. + final ScrollPhysics physics; + @override _TabBarViewState createState() => new _TabBarViewState(); } @@ -954,7 +966,7 @@ class _TabBarViewState extends State { onNotification: _handleScrollNotification, child: new PageView( controller: _pageController, - physics: _kTabBarViewPhysics, + physics: widget.physics == null ? _kTabBarViewPhysics : _kTabBarViewPhysics.applyTo(widget.physics), children: _children, ), ); diff --git a/packages/flutter/test/material/tabs_test.dart b/packages/flutter/test/material/tabs_test.dart index 7e9c0221a3..8812b9c5a8 100644 --- a/packages/flutter/test/material/tabs_test.dart +++ b/packages/flutter/test/material/tabs_test.dart @@ -7,6 +7,7 @@ import 'dart:ui' show SemanticsFlags, SemanticsAction; import 'package:flutter_test/flutter_test.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; +import 'package:flutter/physics.dart'; import '../rendering/mock_canvas.dart'; import '../rendering/recording_canvas.dart'; @@ -128,6 +129,24 @@ class TabIndicatorRecordingCanvas extends TestRecordingCanvas { } } +class TestScrollPhysics extends ScrollPhysics { + const TestScrollPhysics({ ScrollPhysics parent }) : super(parent: parent); + + @override + TestScrollPhysics applyTo(ScrollPhysics ancestor) { + return new TestScrollPhysics(parent: buildParent(ancestor)); + } + + static final SpringDescription _kDefaultSpring = new SpringDescription.withDampingRatio( + mass: 0.5, + springConstant: 500.0, + ratio: 1.1, + ); + + @override + SpringDescription get spring => _kDefaultSpring; +} + void main() { testWidgets('TabBar tap selects tab', (WidgetTester tester) async { final List tabs = ['A', 'B', 'C']; @@ -812,6 +831,53 @@ void main() { expect(tabController.index, 2); }); + testWidgets('TabBarView scrolls end very close to a new page with custom physics', (WidgetTester tester) async { + final TabController tabController = new TabController( + vsync: const TestVSync(), + initialIndex: 1, + length: 3, + ); + + await tester.pumpWidget( + new SizedBox.expand( + child: new Center( + child: new SizedBox( + width: 400.0, + height: 400.0, + child: new TabBarView( + controller: tabController, + physics: const TestScrollPhysics(), + children: [ + const Center(child: const Text('0')), + const Center(child: const Text('1')), + const Center(child: const Text('2')), + ], + ), + ), + ), + ), + ); + + expect(tabController.index, 1); + + final PageView pageView = tester.widget(find.byType(PageView)); + final PageController pageController = pageView.controller; + final ScrollPosition position = pageController.position; + + // The TabBarView's page width is 400, so page 0 is at scroll offset 0.0, + // page 1 is at 400.0, page 2 is at 800.0. + + expect(position.pixels, 400.0); + + // Not close enough to switch to page 2 + pageController.jumpTo(800.0 - 1.25 * position.physics.tolerance.distance); + expect(tabController.index, 1); + + // Close enough to switch to page 2 + pageController.jumpTo(800.0 - 0.75 * position.physics.tolerance.distance); + expect(tabController.index, 2); + }); + testWidgets('Scrollable TabBar with a non-zero TabController initialIndex', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/9374