Unverified Commit 0c80ed6d authored by Kate Lovett's avatar Kate Lovett Committed by GitHub

Keep alive support for 2D scrolling (#131641)

Fixes https://github.com/flutter/flutter/issues/126297

This adds support for keep alive to the 2D scrolling foundation. The TwoDimensionalChildBuilderDelegate and TwoDimensionalChildListDelegate will both add automatic keep alives to their children, matching the convention from SliverChildDelegates. The TwoDimensionalViewportParentData now incorporates keep alive and which is managed by the RenderTwoDimensionalViewport.
parent 9156f6b5
......@@ -395,8 +395,8 @@ class SliverChildBuilderDelegate extends SliverChildDelegate {
/// {@template flutter.widgets.SliverChildBuilderDelegate.addAutomaticKeepAlives}
/// Whether to wrap each child in an [AutomaticKeepAlive].
///
/// Typically, children in lazy list are wrapped in [AutomaticKeepAlive]
/// widgets so that children can use [KeepAliveNotification]s to preserve
/// Typically, lazily laid out children are wrapped in [AutomaticKeepAlive]
/// widgets so that the children can use [KeepAliveNotification]s to preserve
/// their state when they would otherwise be garbage collected off-screen.
///
/// This feature (and [addRepaintBoundaries]) must be disabled if the children
......@@ -863,7 +863,6 @@ Widget _createErrorWidget(Object exception, StackTrace stackTrace) {
return ErrorWidget.builder(details);
}
// TODO(Piinks): Come back and add keep alive support, https://github.com/flutter/flutter/issues/126297
/// A delegate that supplies children for scrolling in two dimensions.
///
/// A [TwoDimensionalScrollView] lazily constructs its box children to avoid
......@@ -929,10 +928,11 @@ class TwoDimensionalChildBuilderDelegate extends TwoDimensionalChildDelegate {
/// Creates a delegate that supplies children for a [TwoDimensionalScrollView]
/// using the given builder callback.
TwoDimensionalChildBuilderDelegate({
this.addRepaintBoundaries = true,
required this.builder,
int? maxXIndex,
int? maxYIndex,
this.addRepaintBoundaries = true,
this.addAutomaticKeepAlives = true,
}) : assert(maxYIndex == null || maxYIndex >= 0),
assert(maxXIndex == null || maxXIndex >= 0),
_maxYIndex = maxYIndex,
......@@ -1028,6 +1028,9 @@ class TwoDimensionalChildBuilderDelegate extends TwoDimensionalChildDelegate {
/// {@macro flutter.widgets.SliverChildBuilderDelegate.addRepaintBoundaries}
final bool addRepaintBoundaries;
/// {@macro flutter.widgets.SliverChildBuilderDelegate.addAutomaticKeepAlives}
final bool addAutomaticKeepAlives;
@override
Widget? build(BuildContext context, ChildVicinity vicinity) {
// If we have exceeded explicit upper bounds, return null.
......@@ -1050,6 +1053,9 @@ class TwoDimensionalChildBuilderDelegate extends TwoDimensionalChildDelegate {
if (addRepaintBoundaries) {
child = RepaintBoundary(child: child);
}
if (addAutomaticKeepAlives) {
child = AutomaticKeepAlive(child: _SelectionKeepAlive(child: child));
}
return child;
}
......@@ -1095,6 +1101,7 @@ class TwoDimensionalChildListDelegate extends TwoDimensionalChildDelegate {
/// null.
TwoDimensionalChildListDelegate({
this.addRepaintBoundaries = true,
this.addAutomaticKeepAlives = true,
required this.children,
});
......@@ -1114,6 +1121,9 @@ class TwoDimensionalChildListDelegate extends TwoDimensionalChildDelegate {
/// {@macro flutter.widgets.SliverChildBuilderDelegate.addRepaintBoundaries}
final bool addRepaintBoundaries;
/// {@macro flutter.widgets.SliverChildBuilderDelegate.addAutomaticKeepAlives}
final bool addAutomaticKeepAlives;
@override
Widget? build(BuildContext context, ChildVicinity vicinity) {
// If we have exceeded explicit upper bounds, return null.
......@@ -1128,7 +1138,9 @@ class TwoDimensionalChildListDelegate extends TwoDimensionalChildDelegate {
if (addRepaintBoundaries) {
child = RepaintBoundary(child: child);
}
if (addAutomaticKeepAlives) {
child = AutomaticKeepAlive(child: _SelectionKeepAlive(child: child));
}
return child;
}
......
......@@ -393,18 +393,18 @@ class RenderSimpleListTableViewport extends RenderTwoDimensionalViewport {
final TwoDimensionalChildListDelegate listDelegate = delegate as TwoDimensionalChildListDelegate;
final int rowCount;
final int columnCount;
rowCount = listDelegate.children.length - 1;
columnCount = listDelegate.children[0].length - 1;
rowCount = listDelegate.children.length;
columnCount = listDelegate.children[0].length;
final int leadingColumn = math.max((horizontalPixels / 200).floor(), 0);
final int leadingRow = math.max((verticalPixels / 200).floor(), 0);
final int trailingColumn = math.min(
((horizontalPixels + viewportDimension.width) / 200).ceil(),
columnCount,
columnCount - 1,
);
final int trailingRow = math.min(
((verticalPixels + viewportDimension.height) / 200).ceil(),
rowCount,
rowCount - 1,
);
double xLayoutOffset = (leadingColumn * 200) - horizontalOffset.pixels;
......@@ -420,7 +420,51 @@ class RenderSimpleListTableViewport extends RenderTwoDimensionalViewport {
}
xLayoutOffset += 200;
}
verticalOffset.applyContentDimensions(0, 200 * 100 - viewportDimension.height);
horizontalOffset.applyContentDimensions(0, 200 * 100 - viewportDimension.width);
verticalOffset.applyContentDimensions(
0.0,
math.max(200 * rowCount - viewportDimension.height, 0.0),
);
horizontalOffset.applyContentDimensions(
0,
math.max(200 * columnCount - viewportDimension.width, 0.0),
);
}
}
class KeepAliveCheckBox extends StatefulWidget {
const KeepAliveCheckBox({ super.key });
@override
KeepAliveCheckBoxState createState() => KeepAliveCheckBoxState();
}
class KeepAliveCheckBoxState extends State<KeepAliveCheckBox> with AutomaticKeepAliveClientMixin {
bool checkValue = false;
@override
bool get wantKeepAlive => _wantKeepAlive;
bool _wantKeepAlive = false;
set wantKeepAlive(bool value) {
if (_wantKeepAlive != value) {
_wantKeepAlive = value;
updateKeepAlive();
}
}
@override
Widget build(BuildContext context) {
super.build(context);
return Checkbox(
value: checkValue,
onChanged: (bool? value) {
if (checkValue != value) {
setState(() {
checkValue = value!;
wantKeepAlive = value;
});
}
},
);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment