Pin widget for some seconds when widget comes into viewport in SliverStreamGrid while scrolling

488 Views Asked by At

I have CustomScrollView with a SliverGrid with different widget types inside. I have a widget that appears after the stream content ends and other content will load. When this widget appears, I want to shortly pin it on the screen and disable the scrolling for 3 seconds.

To simplify it, I skipped the sliver delegates and summarizes my widget tree like this:

CustomScrollView{
  controller: scrollController, 
  slivers: [
    SliverAppBar(),
    SliverStreamGrid(
      children: [
        ProductTile(),
        ProductTile(),
        ProductTile(),
        // End of Available Products
        EndOfProductsInfoWidget(), // should be pinned on screen for 3 seconds
        SomeOtherProductTile(),
        SomeOtherProductTile(),
        SomeOtherProductTile(),
      ]
    )
  ]
}
1

There are 1 best solutions below

1
On

I am using visibility_detector to detect visibility of the widget and SliverPinnedHeader from sliver_tools package. The issue lies when our widget is visible I am using a short delay and then disabling scroll event for 3 seconds, you can use global key for this and have more precious output.

CustomScrollView's physics:NeverScrollableScrollPhysics() used to disable scroll event.

class SliverPinTHEx extends StatefulWidget {
  const SliverPinTHEx({Key? key}) : super(key: key);

  @override
  State<SliverPinTHEx> createState() => _SliverPinTHExState();
}

class _SliverPinTHExState extends State<SliverPinTHEx> {
  bool? _showPinMessage;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: CustomScrollView(
        physics: _showPinMessage == true
            ? const NeverScrollableScrollPhysics()
            : null,
        slivers: [
          list(),
          if (_showPinMessage != false)
            SliverPinnedHeader(
                child: VisibilityDetector(
              onVisibilityChanged: (info) async {
                if (info.visibleFraction == 1.0) {
                  debugPrint("disable scroll");

                  await Future.delayed(const Duration(seconds: 1));
                  setState(() {
                    _showPinMessage = true;
                  });

                  Future.delayed(const Duration(seconds: 3)).then((value) {
                    setState(() {
                      _showPinMessage = false;
                    });
                  });
                }
              },
              key: const Key('my-widget-key'),
              child: Container(
                height: 70,
                color: Colors.amber,
                child: const Text("pinned widget"),
              ),
            )),
          list()
        ],
      ),
    );
  }

  SliverList list() {
    return SliverList(
      delegate: SliverChildBuilderDelegate(
        (context, index) {
          return SizedBox(
            height: 50,
            child: Text(
              index.toString(),
            ),
          );
        },
        childCount: 55,
      ),
    );
  }
}