Whether a viewport is allowed to change its scroll position implicitly in response to a call to [RenderObject.showOnScreen]
[RenderObject.showOnScreen] is for example used to bring a text field fully on screen after it has received focus. This property controls whether the viewport associated with this object is allowed to change the scroll position to fulfill such a request.
// Copyright 2014 The Flutter Authors. All rights reserved.// Use of this source code is governed by a BSD-style license that can be// found in the LICENSE file.import'dart:math'as math;import'package:flutter/foundation.dart'show clampDouble, precisionErrorTolerance;import'package:flutter/gestures.dart'show DragStartBehavior;import'package:flutter/rendering.dart';import'package:flutter/widgets.dart';const PageScrollPhysics _kPagePhysics =PageScrollPhysics();class_ForceImplicitScrollPhysicsextendsScrollPhysics{const_ForceImplicitScrollPhysics({
required this.allowImplicitScrolling,super.parent,});@override
_ForceImplicitScrollPhysics applyTo(ScrollPhysics? ancestor){return_ForceImplicitScrollPhysics(
allowImplicitScrolling: allowImplicitScrolling,
parent:buildParent(ancestor),);}@overridefinal bool allowImplicitScrolling;}/// A scrollable list that works page by page.////// Each child of a page view is forced to be the same size as the viewport.////// You can use a [PageController] to control which page is visible in the view./// In addition to being able to control the pixel offset of the content inside/// the [PageView], a [PageController] also lets you control the offset in terms/// of pages, which are increments of the viewport size.////// The [PageController] can also be used to control the/// [PageController.initialPage], which determines which page is shown when the/// [PageView] is first constructed, and the [PageController.viewportFraction],/// which determines the size of the pages as a fraction of the viewport size.////// {@youtube 560 315 https://www.youtube.com/watch?v=J1gE9xvph-A}////// {@tool dartpad}/// Here is an example of [PageView]. It creates a centered [Text] in each of the three pages/// which scroll horizontally.////// ** See code in examples/api/lib/widgets/page_view/page_view.0.dart **/// {@end-tool}////// ## Persisting the scroll position during a session////// Scroll views attempt to persist their scroll position using [PageStorage]./// For a [PageView], this can be disabled by setting [PageController.keepPage]/// to false on the [controller]. If it is enabled, using a [PageStorageKey] for/// the [key] of this widget is recommended to help disambiguate different/// scroll views from each other.////// See also:////// * [PageController], which controls which page is visible in the view./// * [SingleChildScrollView], when you need to make a single child scrollable./// * [ListView], for a scrollable list of boxes./// * [GridView], for a scrollable grid of boxes./// * [ScrollNotification] and [NotificationListener], which can be used to watch/// the scroll position without using a [ScrollController].classPreloadPageViewextendsStatefulWidget{/// Creates a scrollable list that works page by page from an explicit [List]/// of widgets.////// This constructor is appropriate for page views with a small number of/// children because constructing the [List] requires doing work for every/// child that could possibly be displayed in the page view, instead of just/// those children that are actually visible.////// Like other widgets in the framework, this widget expects that/// the [children] list will not be mutated after it has been passed in here./// See the documentation at [SliverChildListDelegate.children] for more details.////// {@template flutter.widgets.PageView.allowImplicitScrolling}/// If [allowImplicitScrolling] is true, the [PageView] will participate in/// accessibility scrolling more like a [ListView], where implicit scroll/// actions will move to the next page rather than into the contents of the/// [PageView]./// {@endtemplate}PreloadPageView({super.key,this.scrollDirection = Axis.horizontal,this.reverse =false,this.preloadPagesCount =1,this.controller,this.physics,this.pageSnapping =true,this.onPageChanged,
List<Widget> children =const<Widget>[],this.dragStartBehavior = DragStartBehavior.start,this.allowImplicitScrolling =false,this.restorationId,this.clipBehavior = Clip.hardEdge,this.scrollBehavior,this.padEnds =true,}): childrenDelegate =SliverChildListDelegate(children);/// Creates a scrollable list that works page by page using widgets that are/// created on demand.////// This constructor is appropriate for page views with a large (or infinite)/// number of children because the builder is called only for those children/// that are actually visible.////// Providing a non-null [itemCount] lets the [PageView] compute the maximum/// scroll extent.////// [itemBuilder] will be called only with indices greater than or equal to/// zero and less than [itemCount].////// {@macro flutter.widgets.ListView.builder.itemBuilder}////// {@template flutter.widgets.PageView.findChildIndexCallback}/// The [findChildIndexCallback] corresponds to the/// [SliverChildBuilderDelegate.findChildIndexCallback] property. If null,/// a child widget may not map to its existing [RenderObject] when the order/// of children returned from the children builder changes./// This may result in state-loss. This callback needs to be implemented if/// the order of the children may change at a later time./// {@endtemplate}////// {@macro flutter.widgets.PageView.allowImplicitScrolling}
PreloadPageView.builder({super.key,this.scrollDirection = Axis.horizontal,this.reverse =false,this.controller,this.physics,this.preloadPagesCount =1,this.pageSnapping =true,this.onPageChanged,
required NullableIndexedWidgetBuilder itemBuilder,
ChildIndexGetter? findChildIndexCallback,
int? itemCount,this.dragStartBehavior = DragStartBehavior.start,this.allowImplicitScrolling =false,this.restorationId,this.clipBehavior = Clip.hardEdge,this.scrollBehavior,this.padEnds =true,}): childrenDelegate =SliverChildBuilderDelegate(
itemBuilder,
findChildIndexCallback: findChildIndexCallback,
childCount: itemCount,);/// Creates a scrollable list that works page by page with a custom child/// model.////// {@tool dartpad}/// This example shows a [PageView] that uses a custom [SliverChildBuilderDelegate] to support child/// reordering.////// ** See code in examples/api/lib/widgets/page_view/page_view.1.dart **/// {@end-tool}////// {@macro flutter.widgets.PageView.allowImplicitScrolling}const PreloadPageView.custom({super.key,this.scrollDirection = Axis.horizontal,this.reverse =false,this.controller,this.physics,this.preloadPagesCount =1,this.pageSnapping =true,this.onPageChanged,
required this.childrenDelegate,this.dragStartBehavior = DragStartBehavior.start,this.allowImplicitScrolling =false,this.restorationId,this.clipBehavior = Clip.hardEdge,this.scrollBehavior,this.padEnds =true,});final int preloadPagesCount;/// Controls whether the widget's pages will respond to/// [RenderObject.showOnScreen], which will allow for implicit accessibility/// scrolling.////// With this flag set to false, when accessibility focus reaches the end of/// the current page and the user attempts to move it to the next element, the/// focus will traverse to the next widget outside of the page view.////// With this flag set to true, when accessibility focus reaches the end of/// the current page and user attempts to move it to the next element, focus/// will traverse to the next page in the page view.final bool allowImplicitScrolling;/// {@macro flutter.widgets.scrollable.restorationId}final String? restorationId;/// The [Axis] along which the scroll view's offset increases with each page.////// For the direction in which active scrolling may be occurring, see/// [ScrollDirection].////// Defaults to [Axis.horizontal].final Axis scrollDirection;/// Whether the page view scrolls in the reading direction.////// For example, if the reading direction is left-to-right and/// [scrollDirection] is [Axis.horizontal], then the page view scrolls from/// left to right when [reverse] is false and from right to left when/// [reverse] is true.////// Similarly, if [scrollDirection] is [Axis.vertical], then the page view/// scrolls from top to bottom when [reverse] is false and from bottom to top/// when [reverse] is true.////// Defaults to false.final bool reverse;/// An object that can be used to control the position to which this page/// view is scrolled.final PageController? controller;/// 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.////// If an explicit [ScrollBehavior] is provided to [scrollBehavior], the/// [ScrollPhysics] provided by that behavior will take precedence after/// [physics].////// Defaults to matching platform conventions.final ScrollPhysics? physics;/// Set to false to disable page snapping, useful for custom scroll behavior.////// If the [padEnds] is false and [PageController.viewportFraction] < 1.0,/// the page will snap to the beginning of the viewport; otherwise, the page/// will snap to the center of the viewport.final bool pageSnapping;/// Called whenever the page in the center of the viewport changes.final ValueChanged<int>? onPageChanged;/// A delegate that provides the children for the [PageView].////// The [PageView.custom] constructor lets you specify this delegate/// explicitly. The [PageView] and [PageView.builder] constructors create a/// [childrenDelegate] that wraps the given [List] and [IndexedWidgetBuilder],/// respectively.final SliverChildDelegate childrenDelegate;/// {@macro flutter.widgets.scrollable.dragStartBehavior}final DragStartBehavior dragStartBehavior;/// {@macro flutter.material.Material.clipBehavior}////// Defaults to [Clip.hardEdge].final Clip clipBehavior;/// {@macro flutter.widgets.shadow.scrollBehavior}////// [ScrollBehavior]s also provide [ScrollPhysics]. If an explicit/// [ScrollPhysics] is provided in [physics], it will take precedence,/// followed by [scrollBehavior], and then the inherited ancestor/// [ScrollBehavior].////// The [ScrollBehavior] of the inherited [ScrollConfiguration] will be/// modified by default to not apply a [Scrollbar].final ScrollBehavior? scrollBehavior;/// Whether to add padding to both ends of the list.////// If this is set to true and [PageController.viewportFraction] < 1.0, padding will be added/// such that the first and last child slivers will be in the center of/// the viewport when scrolled all the way to the start or end, respectively.////// If [PageController.viewportFraction] >= 1.0, this property has no effect.////// This property defaults to true.final bool padEnds;@override
State<PreloadPageView>createState()=>_PreloadPageViewState();}class_PreloadPageViewStateextendsState<PreloadPageView>{
int _lastReportedPage =0;
late PageController _controller;@overridevoidinitState(){super.initState();_initController();
_lastReportedPage = _controller.initialPage;}@overridevoiddispose(){if(widget.controller ==null){
_controller.dispose();}super.dispose();}void_initController(){
_controller = widget.controller ??PageController();}@overridevoiddidUpdateWidget(PreloadPageView oldWidget){if(oldWidget.controller != widget.controller){if(oldWidget.controller ==null){
_controller.dispose();}_initController();}super.didUpdateWidget(oldWidget);}
AxisDirection _getDirection(BuildContext context){switch(widget.scrollDirection){case Axis.horizontal:assert(debugCheckHasDirectionality(context));final TextDirection textDirection = Directionality.of(context);final AxisDirection axisDirection =textDirectionToAxisDirection(textDirection);return widget.reverse ?flipAxisDirection(axisDirection): axisDirection;case Axis.vertical:return widget.reverse ? AxisDirection.up : AxisDirection.down;}}@override
Widget build(BuildContext context){final AxisDirection axisDirection =_getDirection(context);final ScrollPhysics physics =_ForceImplicitScrollPhysics(
allowImplicitScrolling: widget.allowImplicitScrolling,).applyTo(
widget.pageSnapping
? _kPagePhysics.applyTo(widget.physics ?? widget.scrollBehavior?.getScrollPhysics(context)): widget.physics ?? widget.scrollBehavior?.getScrollPhysics(context),);return NotificationListener<ScrollNotification>(
onNotification:(ScrollNotification notification){if(notification.depth ==0&& widget.onPageChanged !=null&& notification is ScrollUpdateNotification){final PageMetrics metrics = notification.metrics as PageMetrics;final int currentPage = metrics.page!.round();if(currentPage != _lastReportedPage){
_lastReportedPage = currentPage;
widget.onPageChanged!(currentPage);}}returnfalse;},
child:Scrollable(
dragStartBehavior: widget.dragStartBehavior,
axisDirection: axisDirection,
controller: _controller,
physics: physics,
restorationId: widget.restorationId,
scrollBehavior: widget.scrollBehavior ?? ScrollConfiguration.of(context).copyWith(scrollbars:false),
viewportBuilder:(BuildContext context, ViewportOffset position){returnViewport(// TODO(dnfield): we should provide a way to set cacheExtent// independent of implicit scrolling:// https://github.com/flutter/flutter/issues/45632
cacheExtent: widget.preloadPagesCount <1?0:(widget.preloadPagesCount ==1?1: widget.scrollDirection == Axis.horizontal
? MediaQuery.of(context).size.width *
widget.preloadPagesCount -1: MediaQuery.of(context).size.height *
widget.preloadPagesCount -1),
cacheExtentStyle: CacheExtentStyle.viewport,
axisDirection: axisDirection,
offset: position,
clipBehavior: widget.clipBehavior,
slivers:<Widget>[SliverFillViewport(
viewportFraction: _controller.viewportFraction,
delegate: widget.childrenDelegate,
padEnds: widget.padEnds,),],);},),);}@overridevoiddebugFillProperties(DiagnosticPropertiesBuilder description){super.debugFillProperties(description);
description.add(EnumProperty<Axis>('scrollDirection', widget.scrollDirection));
description.add(FlagProperty('reverse', value: widget.reverse, ifTrue:'reversed'));
description.add(DiagnosticsProperty<PageController>('controller', _controller, showName:false));
description.add(DiagnosticsProperty<ScrollPhysics>('physics', widget.physics, showName:false));
description.add(FlagProperty('pageSnapping', value: widget.pageSnapping, ifFalse:'snapping disabled'));
description.add(FlagProperty('allowImplicitScrolling', value: widget.allowImplicitScrolling, ifTrue:'allow implicit scrolling'));}}