Home > front end >  Slivers equivalent for StatelessWidget
Slivers equivalent for StatelessWidget

Time:11-21

Which class to extend when creating slivers?

Say, I have a class FooSliver which returns a widget.

class FooSliver extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaybeSliverWidget(...);
  }
}

But I can't use this class directly in my slivers if the above class returns a non-sliver widget i.e. a RenderObject.

CustomScrollView(
  slivers: [
    FooSliver(),
  ],
)

So, which sliver class should I extend instead of StatelessWidget to make sure I always return a sliver widget from it?

CodePudding user response:

You can create your custom sliver. You need to create a custom RenderSliverSingleBoxAdapter and SingleChildRenderObjectWidget

class FooSliver extends SingleChildRenderObjectWidget {
  const FooSliver({super.key, super.child});

  @override
  RenderObject createRenderObject(BuildContext context) => FooRenderSliver();
}

class BarSliver extends SingleChildRenderObjectWidget {
  const BarSliver({super.key, super.child = const Text("Hello from Bar")});

  @override
  RenderObject createRenderObject(BuildContext context) => FooRenderSliver();
}

class FooRenderSliver extends RenderSliverSingleBoxAdapter {
  FooRenderSliver({super.child});

  @override
  void performLayout() {
    /// from  [RenderSliverToBoxAdapter]
    if (child == null) {
      geometry = SliverGeometry.zero;
      return;
    }
    final SliverConstraints constraints = this.constraints;
    child!.layout(constraints.asBoxConstraints(), parentUsesSize: true);
    final double childExtent;
    switch (constraints.axis) {
      case Axis.horizontal:
        childExtent = child!.size.width;
        break;
      case Axis.vertical:
        childExtent = child!.size.height;
        break;
    }
    assert(childExtent != null);
    final double paintedChildSize =
        calculatePaintOffset(constraints, from: 0.0, to: childExtent);
    final double cacheExtent =
        calculateCacheOffset(constraints, from: 0.0, to: childExtent);

    assert(paintedChildSize.isFinite);
    assert(paintedChildSize >= 0.0);
    geometry = SliverGeometry(
      scrollExtent: childExtent,
      paintExtent: paintedChildSize,
      cacheExtent: cacheExtent,
      maxPaintExtent: childExtent,
      hitTestExtent: paintedChildSize,
      hasVisualOverflow: childExtent > constraints.remainingPaintExtent ||
          constraints.scrollOffset > 0.0,
    );
    setChildParentData(child!, constraints, geometry!);
  }
}

And use like

home: Scaffold(
  body: CustomScrollView(
    slivers: [
      FooSliver(
        child: Text("Hi From Foo sliver"),
      ),
      BarSliver()
    ],
  ),
),

More about RenderSliver

  • Related