Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter SliverList with horizontal scrolling and sticky header

I've been trying for a while now but I cannot get it to work.

I want to create a list view in a CustomScrollView with a CupertinoSliverNavigationBar. The SliverList has to be scrollable horizontally. Also, it should have one header row that sticks to the top of the view.

Please see the example here: https://dartpad.dev/?id=38c0825f27c1b3395dd22794a2567e64. Note that the body can be scrolled horizontally.

I want to make the red header row sticky so that it remains visible at all times while the blue content is scrolling.

Problem is that the header row must be inside the SingleChildScrollView and the SizedBox because otherwise it would not have the required width. But once it is inside there I cannot make it sticky anymore.

Many thanks for any pointers.

like image 932
wackazong Avatar asked Oct 20 '25 04:10

wackazong


1 Answers

Solution ^^ use SliverPersistentHeader to make the red header row sticky and use SliverList instead of ListView.

import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'dart:math' as math;

class HomePage extends StatelessWidget {
   const HomePage({Key? key}) : super(key: key);


 @override
   Widget build(BuildContext context) {
final scrollController = ScrollController();
return MaterialApp(
  home: Scaffold(
    body: CustomScrollView(
      slivers: [
        const CupertinoSliverNavigationBar(
          largeTitle: Text('Search'),
        ),
        //CupertinoSliverRefreshControl(),
        SliverPersistentHeader(
          pinned: true,
          delegate: _SliverAppBarDelegate(
            minHeight: 20.0,
            maxHeight: 30.0,
            child: Container(
                color: Colors.red, child: Center(child:
            Text("red header "))),
          ),
        ),

        SliverList(
          delegate: SliverChildListDelegate(
            List.generate(80, (index) => Container(
              padding: const EdgeInsets.all(5),
              color: Colors.blueAccent.shade100,
              child: const Text('bar'),
            )),
          ),
        ),

       ],
    ),
  ),
);
   }
}

class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
   _SliverAppBarDelegate({
       required this.minHeight,
      required this.maxHeight,
      required this.child,
    });

    final double minHeight;
    final double maxHeight;
    final Widget child;

    @override
     double get minExtent => minHeight;

    @override
     double get maxExtent => math.max(maxHeight, minHeight);

    @override
     Widget build(BuildContext context,
      double shrinkOffset,
      bool overlapsContent) {
     return new SizedBox.expand(child: child);
      }

    @override
    bool shouldRebuild(_SliverAppBarDelegate oldDelegate) {
      return maxHeight != oldDelegate.maxHeight ||
      minHeight != oldDelegate.minHeight ||
       child != oldDelegate.child;
    }
   }
like image 103
Imen A. Avatar answered Oct 22 '25 00:10

Imen A.



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!