Unverified Commit 825e901e authored by Victoria Ashworth's avatar Victoria Ashworth Committed by GitHub

Set cacheExtent for SliverFillRemaining widget (#143612)

When a Sliver with items is outside of the Viewport, but within the Viewport's `cacheExtent`, the framework should create SemanticNodes for the items even though they are out of view. However, for this to work, the Sliver's geometry must have a `cacheExtent` (how much space the sliver took up of the Viewport's `cacheExtent`) greater than 0, otherwise it is [excluded](https://github.com/flutter/flutter/blob/f01ce9f4cb41beff7b85122b5fcf1228bb655a87/packages/flutter/lib/src/rendering/viewport.dart#L311-L315).

`SliverFillRemaining` widgets that fall outside the viewport did not have this set and therefore were being excluded when SemanticNodes were created, even if they were within the Viewport's `cacheExtent`. This PR sets the `cacheExtent` for `SliverFillRemaining` widgets.

In addition, `RenderSliverFillRemainingWithScrollable` would get dropped from the semantic tree because it's child had a size of 0 when outside the remaining paint extent. To fix, we give the child a `maxExtent` of the sliver's `cacheExtent` if it's outside the remaining paint extent but within the viewport's cacheExtent.

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

Definitions:
* `RenderViewport.cacheExtent`:
  ```dart
  /// The viewport has an area before and after the visible area to cache items
  /// that are about to become visible when the user scrolls.
  ///
  /// Items that fall in this cache area are laid out even though they are not
  /// (yet) visible on screen. The [cacheExtent] describes how many pixels
  /// the cache area extends before the leading edge and after the trailing edge
  /// of the viewport.
  ///
  /// The total extent, which the viewport will try to cover with children, is
  /// [cacheExtent] before the leading edge + extent of the main axis +
  /// [cacheExtent] after the trailing edge.
  ///
  /// The cache area is also used to implement implicit accessibility scrolling
  /// on iOS: When the accessibility focus moves from an item in the visible
  /// viewport to an invisible item in the cache area, the framework will bring
  /// that item into view with an (implicit) scroll action.
  ```
* `SliverGeometry.cacheExtent`:
  ```dart
  /// How many pixels the sliver has consumed in the
  /// [SliverConstraints.remainingCacheExtent].
  ```
* `SliverContraints.remainingCacheExtent`:
  ```dart
  /// Describes how much content the sliver should provide starting from the
  /// [cacheOrigin].
  ///
  /// Not all content in the [remainingCacheExtent] will be visible as some
  /// of it might fall into the cache area of the viewport.
  ///
  /// Each sliver should start laying out content at the [cacheOrigin] and
  /// try to provide as much content as the [remainingCacheExtent] allows.
  ```
parent 1ccad1a2
......@@ -83,21 +83,36 @@ class RenderSliverFillRemainingWithScrollable extends RenderSliverSingleBoxAdapt
final SliverConstraints constraints = this.constraints;
final double extent = constraints.remainingPaintExtent - math.min(constraints.overlap, 0.0);
final double cacheExtent = calculateCacheOffset(
constraints,
from: 0.0,
to: constraints.viewportMainAxisExtent,
);
if (child != null) {
double maxExtent = extent;
// If sliver has no extent, but is within viewport's cacheExtent, use the
// sliver's cacheExtent as the maxExtent so that it does not get dropped
// from the semantic tree.
if (extent == 0 && cacheExtent > 0) {
maxExtent = cacheExtent;
}
child!.layout(constraints.asBoxConstraints(
minExtent: extent,
maxExtent: extent,
maxExtent: maxExtent,
));
}
final double paintedChildSize = calculatePaintOffset(constraints, from: 0.0, to: extent);
assert(paintedChildSize.isFinite);
assert(paintedChildSize >= 0.0);
geometry = SliverGeometry(
scrollExtent: constraints.viewportMainAxisExtent,
paintExtent: paintedChildSize,
maxPaintExtent: paintedChildSize,
hasVisualOverflow: extent > constraints.remainingPaintExtent || constraints.scrollOffset > 0.0,
cacheExtent: cacheExtent,
);
if (child != null) {
setChildParentData(child!, constraints, geometry!);
......@@ -162,11 +177,14 @@ class RenderSliverFillRemaining extends RenderSliverSingleBoxAdapter {
final double paintedChildSize = calculatePaintOffset(constraints, from: 0.0, to: extent);
assert(paintedChildSize.isFinite);
assert(paintedChildSize >= 0.0);
final double cacheExtent = calculateCacheOffset(constraints, from: 0.0, to: extent);
geometry = SliverGeometry(
scrollExtent: extent,
paintExtent: paintedChildSize,
maxPaintExtent: paintedChildSize,
hasVisualOverflow: extent > constraints.remainingPaintExtent || constraints.scrollOffset > 0.0,
cacheExtent: cacheExtent,
);
if (child != null) {
setChildParentData(child!, constraints, geometry!);
......@@ -235,11 +253,14 @@ class RenderSliverFillRemainingAndOverscroll extends RenderSliverSingleBoxAdapte
final double paintedChildSize = calculatePaintOffset(constraints, from: 0.0, to: extent);
assert(paintedChildSize.isFinite);
assert(paintedChildSize >= 0.0);
final double cacheExtent = calculateCacheOffset(constraints, from: 0.0, to: extent);
geometry = SliverGeometry(
scrollExtent: extent,
paintExtent: math.min(maxExtent, constraints.remainingPaintExtent),
maxPaintExtent: maxExtent,
hasVisualOverflow: extent > constraints.remainingPaintExtent || constraints.scrollOffset > 0.0,
cacheExtent: cacheExtent,
);
if (child != null) {
setChildParentData(child!, constraints, geometry!);
......
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