Add a pageSnapping parameter to PageView (#12596)
* Add a pageSnapping parameter to PageView Setting the pageSnapping property allows extending the PageView scroll behavior, such as custom scroll animations or custom scroll bars. * Apply pageSnapping CR feedback - Remove _kNonSnappingPhysics, use null instead. - Minor code style fixes. - It turns out that the forth state is Arkansas, not California.
This commit is contained in:
parent
ea679171e5
commit
021a268852
@ -344,6 +344,7 @@ class PageView extends StatefulWidget {
|
||||
this.reverse: false,
|
||||
PageController controller,
|
||||
this.physics,
|
||||
this.pageSnapping: true,
|
||||
this.onPageChanged,
|
||||
List<Widget> children: const <Widget>[],
|
||||
}) : controller = controller ?? _defaultPageController,
|
||||
@ -368,6 +369,7 @@ class PageView extends StatefulWidget {
|
||||
this.reverse: false,
|
||||
PageController controller,
|
||||
this.physics,
|
||||
this.pageSnapping: true,
|
||||
this.onPageChanged,
|
||||
@required IndexedWidgetBuilder itemBuilder,
|
||||
int itemCount,
|
||||
@ -383,6 +385,7 @@ class PageView extends StatefulWidget {
|
||||
this.reverse: false,
|
||||
PageController controller,
|
||||
this.physics,
|
||||
this.pageSnapping: true,
|
||||
this.onPageChanged,
|
||||
@required this.childrenDelegate,
|
||||
}) : assert(childrenDelegate != null),
|
||||
@ -423,6 +426,9 @@ class PageView extends StatefulWidget {
|
||||
/// Defaults to matching platform conventions.
|
||||
final ScrollPhysics physics;
|
||||
|
||||
/// Set to false to disable page snapping, useful for custom scroll behavior.
|
||||
final bool pageSnapping;
|
||||
|
||||
/// Called whenever the page in the center of the viewport changes.
|
||||
final ValueChanged<int> onPageChanged;
|
||||
|
||||
@ -463,6 +469,10 @@ class _PageViewState extends State<PageView> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final AxisDirection axisDirection = _getDirection(context);
|
||||
final ScrollPhysics physics = widget.pageSnapping
|
||||
? _kPagePhysics.applyTo(widget.physics)
|
||||
: widget.physics;
|
||||
|
||||
return new NotificationListener<ScrollNotification>(
|
||||
onNotification: (ScrollNotification notification) {
|
||||
if (notification.depth == 0 && widget.onPageChanged != null && notification is ScrollUpdateNotification) {
|
||||
@ -478,7 +488,7 @@ class _PageViewState extends State<PageView> {
|
||||
child: new Scrollable(
|
||||
axisDirection: axisDirection,
|
||||
controller: widget.controller,
|
||||
physics: widget.physics == null ? _kPagePhysics : _kPagePhysics.applyTo(widget.physics),
|
||||
physics: physics,
|
||||
viewportBuilder: (BuildContext context, ViewportOffset position) {
|
||||
return new Viewport(
|
||||
axisDirection: axisDirection,
|
||||
@ -502,5 +512,6 @@ class _PageViewState extends State<PageView> {
|
||||
description.add(new FlagProperty('reverse', value: widget.reverse, ifTrue: 'reversed'));
|
||||
description.add(new DiagnosticsProperty<PageController>('controller', widget.controller, showName: false));
|
||||
description.add(new DiagnosticsProperty<ScrollPhysics>('physics', widget.physics, showName: false));
|
||||
description.add(new FlagProperty('pageSnapping', value: widget.pageSnapping, ifFalse: 'snapping disabled'));
|
||||
}
|
||||
}
|
||||
|
@ -368,6 +368,69 @@ void main() {
|
||||
expect(tester.getTopLeft(find.text('Idaho')), const Offset(790.0, 0.0));
|
||||
});
|
||||
|
||||
testWidgets('Page snapping disable and reenable', (WidgetTester tester) async {
|
||||
final List<int> log = <int>[];
|
||||
|
||||
Widget build({ bool pageSnapping }) {
|
||||
return new Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: new PageView(
|
||||
pageSnapping: pageSnapping,
|
||||
onPageChanged: log.add,
|
||||
children:
|
||||
kStates.map<Widget>((String state) => new Text(state)).toList(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
await tester.pumpWidget(build(pageSnapping: true));
|
||||
expect(log, isEmpty);
|
||||
|
||||
// Drag more than halfway to the next page, to confirm the default behavior.
|
||||
TestGesture gesture = await tester.startGesture(const Offset(100.0, 100.0));
|
||||
// The page view is 800.0 wide, so this move is just beyond halfway.
|
||||
await gesture.moveBy(const Offset(-420.0, 0.0));
|
||||
|
||||
expect(log, equals(const <int>[1]));
|
||||
log.clear();
|
||||
|
||||
// Release the gesture, confirm that the page settles on the next.
|
||||
await gesture.up();
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Alabama'), findsNothing);
|
||||
expect(find.text('Alaska'), findsOneWidget);
|
||||
|
||||
// Disable page snapping, and try moving halfway. Confirm it doesn't snap.
|
||||
await tester.pumpWidget(build(pageSnapping: false));
|
||||
gesture = await tester.startGesture(const Offset(100.0, 100.0));
|
||||
// Move just beyond halfway, again.
|
||||
await gesture.moveBy(const Offset(-420.0, 0.0));
|
||||
|
||||
// Page notifications still get sent.
|
||||
expect(log, equals(const <int>[2]));
|
||||
log.clear();
|
||||
|
||||
// Release the gesture, confirm that both pages are visible.
|
||||
await gesture.up();
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Alabama'), findsNothing);
|
||||
expect(find.text('Alaska'), findsOneWidget);
|
||||
expect(find.text('Arizona'), findsOneWidget);
|
||||
expect(find.text('Arkansas'), findsNothing);
|
||||
|
||||
// Now re-enable snapping, confirm that we've settled on a page.
|
||||
await tester.pumpWidget(build(pageSnapping: true));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(log, isEmpty);
|
||||
|
||||
expect(find.text('Alaska'), findsNothing);
|
||||
expect(find.text('Arizona'), findsOneWidget);
|
||||
expect(find.text('Arkansas'), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('PageView small viewportFraction', (WidgetTester tester) async {
|
||||
final PageController controller = new PageController(viewportFraction: 1/8);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user