-
Notifications
You must be signed in to change notification settings - Fork 608
Open
Description
First of all, I apologize for using a translator because my English is not good.
I would like to preload images for the user's convenience.
I was looking at your code and noticed that you were using PageView and I just happened to find an improved PageView code.
flutter/flutter#31191 (comment)
The code below shows the improved PageView content.
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
// this 100% copied from flutter source code
// only change is to add cacheExtent to Viewport
// by doing this we can cache the pages in PageView
// source code: packages/flutter/lib/src/widgets/page_view.dart
// closed PR: https://github.com/flutter/flutter/pull/42107/
// all credits goes to https://github.com/lukepighetti
//
class CacheablePageView extends StatefulWidget {
CacheablePageView({
super.key,
this.scrollDirection = Axis.horizontal,
this.reverse = false,
PageController? controller,
this.physics,
this.pageSnapping = true,
this.onPageChanged,
List<Widget> children = const <Widget>[],
this.dragStartBehavior = DragStartBehavior.start,
this.cachePageExtent = 0,
this.allowImplicitScrolling = false,
this.restorationId,
this.clipBehavior = Clip.hardEdge,
this.scrollBehavior,
this.padEnds = true,
}) : controller = controller ?? _defaultPageController,
childrenDelegate = SliverChildListDelegate(children);
CacheablePageView.builder({
super.key,
this.scrollDirection = Axis.horizontal,
this.reverse = false,
PageController? controller,
this.physics,
this.pageSnapping = true,
this.onPageChanged,
required NullableIndexedWidgetBuilder itemBuilder,
ChildIndexGetter? findChildIndexCallback,
int? itemCount,
this.dragStartBehavior = DragStartBehavior.start,
this.cachePageExtent = 0,
this.allowImplicitScrolling = false,
this.restorationId,
this.clipBehavior = Clip.hardEdge,
this.scrollBehavior,
this.padEnds = true,
}) : controller = controller ?? _defaultPageController,
childrenDelegate = SliverChildBuilderDelegate(
itemBuilder,
findChildIndexCallback: findChildIndexCallback,
childCount: itemCount,
);
CacheablePageView.custom({
super.key,
this.scrollDirection = Axis.horizontal,
this.reverse = false,
PageController? controller,
this.physics,
this.pageSnapping = true,
this.onPageChanged,
required this.childrenDelegate,
this.dragStartBehavior = DragStartBehavior.start,
this.cachePageExtent = 0,
this.allowImplicitScrolling = false,
this.restorationId,
this.clipBehavior = Clip.hardEdge,
this.scrollBehavior,
this.padEnds = true,
}) : controller = controller ?? _defaultPageController;
final bool allowImplicitScrolling;
final String? restorationId;
final Axis scrollDirection;
final bool reverse;
final PageController controller;
final ScrollPhysics? physics;
final bool pageSnapping;
final ValueChanged<int>? onPageChanged;
final SliverChildDelegate childrenDelegate;
final DragStartBehavior dragStartBehavior;
final int cachePageExtent;
final Clip clipBehavior;
final ScrollBehavior? scrollBehavior;
final bool padEnds;
@override
State<CacheablePageView> createState() => _CacheablePageViewState();
}
class _CacheablePageViewState extends State<CacheablePageView> {
int _lastReportedPage = 0;
@override
void initState() {
super.initState();
_lastReportedPage = widget.controller.initialPage;
}
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);
}
}
return false;
},
child: Scrollable(
dragStartBehavior: widget.dragStartBehavior,
axisDirection: axisDirection,
controller: widget.controller,
physics: physics,
restorationId: widget.restorationId,
scrollBehavior: widget.scrollBehavior ??
ScrollConfiguration.of(context).copyWith(scrollbars: false),
viewportBuilder: (BuildContext context, ViewportOffset position) {
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
double cacheExtent;
switch (widget.scrollDirection) {
case Axis.vertical:
cacheExtent = constraints.maxHeight * widget.cachePageExtent;
break;
case Axis.horizontal:
cacheExtent = constraints.maxWidth * widget.cachePageExtent;
break;
}
return Viewport(
cacheExtent: cacheExtent,
axisDirection: axisDirection,
offset: position,
slivers: <Widget>[
SliverFillViewport(
viewportFraction: widget.controller.viewportFraction,
delegate: widget.childrenDelegate,
),
],
);
});
},
),
);
}
@override
void debugFillProperties(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', widget.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'));
}
}
class _ForceImplicitScrollPhysics extends ScrollPhysics {
const _ForceImplicitScrollPhysics({
required this.allowImplicitScrolling,
super.parent,
});
@override
_ForceImplicitScrollPhysics applyTo(ScrollPhysics? ancestor) {
return _ForceImplicitScrollPhysics(
allowImplicitScrolling: allowImplicitScrolling,
parent: buildParent(ancestor),
);
}
@override
final bool allowImplicitScrolling;
}
final PageController _defaultPageController = PageController();
const PageScrollPhysics _kPagePhysics = PageScrollPhysics();I would like to add preload functionality using the above code.
Thank you for listening to my opinion.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels