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,
|
this.reverse: false,
|
||||||
PageController controller,
|
PageController controller,
|
||||||
this.physics,
|
this.physics,
|
||||||
|
this.pageSnapping: true,
|
||||||
this.onPageChanged,
|
this.onPageChanged,
|
||||||
List<Widget> children: const <Widget>[],
|
List<Widget> children: const <Widget>[],
|
||||||
}) : controller = controller ?? _defaultPageController,
|
}) : controller = controller ?? _defaultPageController,
|
||||||
@ -368,6 +369,7 @@ class PageView extends StatefulWidget {
|
|||||||
this.reverse: false,
|
this.reverse: false,
|
||||||
PageController controller,
|
PageController controller,
|
||||||
this.physics,
|
this.physics,
|
||||||
|
this.pageSnapping: true,
|
||||||
this.onPageChanged,
|
this.onPageChanged,
|
||||||
@required IndexedWidgetBuilder itemBuilder,
|
@required IndexedWidgetBuilder itemBuilder,
|
||||||
int itemCount,
|
int itemCount,
|
||||||
@ -383,6 +385,7 @@ class PageView extends StatefulWidget {
|
|||||||
this.reverse: false,
|
this.reverse: false,
|
||||||
PageController controller,
|
PageController controller,
|
||||||
this.physics,
|
this.physics,
|
||||||
|
this.pageSnapping: true,
|
||||||
this.onPageChanged,
|
this.onPageChanged,
|
||||||
@required this.childrenDelegate,
|
@required this.childrenDelegate,
|
||||||
}) : assert(childrenDelegate != null),
|
}) : assert(childrenDelegate != null),
|
||||||
@ -423,6 +426,9 @@ class PageView extends StatefulWidget {
|
|||||||
/// Defaults to matching platform conventions.
|
/// Defaults to matching platform conventions.
|
||||||
final ScrollPhysics physics;
|
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.
|
/// Called whenever the page in the center of the viewport changes.
|
||||||
final ValueChanged<int> onPageChanged;
|
final ValueChanged<int> onPageChanged;
|
||||||
|
|
||||||
@ -463,6 +469,10 @@ class _PageViewState extends State<PageView> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final AxisDirection axisDirection = _getDirection(context);
|
final AxisDirection axisDirection = _getDirection(context);
|
||||||
|
final ScrollPhysics physics = widget.pageSnapping
|
||||||
|
? _kPagePhysics.applyTo(widget.physics)
|
||||||
|
: widget.physics;
|
||||||
|
|
||||||
return new NotificationListener<ScrollNotification>(
|
return new NotificationListener<ScrollNotification>(
|
||||||
onNotification: (ScrollNotification notification) {
|
onNotification: (ScrollNotification notification) {
|
||||||
if (notification.depth == 0 && widget.onPageChanged != null && notification is ScrollUpdateNotification) {
|
if (notification.depth == 0 && widget.onPageChanged != null && notification is ScrollUpdateNotification) {
|
||||||
@ -478,7 +488,7 @@ class _PageViewState extends State<PageView> {
|
|||||||
child: new Scrollable(
|
child: new Scrollable(
|
||||||
axisDirection: axisDirection,
|
axisDirection: axisDirection,
|
||||||
controller: widget.controller,
|
controller: widget.controller,
|
||||||
physics: widget.physics == null ? _kPagePhysics : _kPagePhysics.applyTo(widget.physics),
|
physics: physics,
|
||||||
viewportBuilder: (BuildContext context, ViewportOffset position) {
|
viewportBuilder: (BuildContext context, ViewportOffset position) {
|
||||||
return new Viewport(
|
return new Viewport(
|
||||||
axisDirection: axisDirection,
|
axisDirection: axisDirection,
|
||||||
@ -502,5 +512,6 @@ class _PageViewState extends State<PageView> {
|
|||||||
description.add(new FlagProperty('reverse', value: widget.reverse, ifTrue: 'reversed'));
|
description.add(new FlagProperty('reverse', value: widget.reverse, ifTrue: 'reversed'));
|
||||||
description.add(new DiagnosticsProperty<PageController>('controller', widget.controller, showName: false));
|
description.add(new DiagnosticsProperty<PageController>('controller', widget.controller, showName: false));
|
||||||
description.add(new DiagnosticsProperty<ScrollPhysics>('physics', widget.physics, 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));
|
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 {
|
testWidgets('PageView small viewportFraction', (WidgetTester tester) async {
|
||||||
final PageController controller = new PageController(viewportFraction: 1/8);
|
final PageController controller = new PageController(viewportFraction: 1/8);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user