anchor.diff:      assert(_offsets[index] < endScrollOffset);
       return index;
     }
  +}
  +
  +class FixedExtentDelegate extends FixedExtentDelegateBase {
  +  FixedExtentDelegate({
  +    @required double Function(int index) computeExtent,
  +    @required int Function() computeLength,
  +  })  : _computeExtent = computeExtent,
  +        _computeLength = computeLength {
  +    recompute();
  +  }
  +
  +  final double Function(int index) _computeExtent;
  +  final int Function() _computeLength;
  +
  +  @override
  +  double computeExtent(int index) => _computeExtent(index);
  +
  +  @override
  +  int computeLength() => _computeLength();
   }
   
   /// A scrollable list of widgets arranged linearly where each item has an extent
  
positive.code:           }
            max = _extentDelegate.layoutOffset(possibleFirstIndex);
          }
          geometry = SliverGeometry(
            scrollExtent: _extentDelegate.layoutOffset(_extentDelegate.length),
            maxPaintExtent: max,
  
negative.code:     @required RenderSliverBoxChildManager childManager,
      @required ExtentDelegate extentDelegate,
    }) : super(childManager: childManager) {
      _markNeedsLayout = markNeedsLayout;
      this.extentDelegate = extentDelegate;
    }
  
    set extentDelegate(ExtentDelegate delegate) {
      if (delegate == _extentDelegate) return;
      assert(_markNeedsLayout != null);
  
      // Unregister from the previous delegate if there was one.
      if (_extentDelegate != null) {
        _extentDelegate.layoutDirty.removeListener(_markNeedsLayout);
      }
  
      // We need to listen for when the delegate changes its layout.
      delegate.layoutDirty.addListener(_markNeedsLayout);
      _extentDelegate = delegate;
    }
  
    ExtentDelegate _extentDelegate;
    VoidCallback _markNeedsLayout;
  
    /// Called to estimate the total scrollable extents of this object.
    ///
  