import 'dart:math' as math; import 'package:flutter/material.dart'; extension SliverListEx on SliverList { static SliverList separated({ required int itemCount, required NullableIndexedWidgetBuilder itemBuilder, required NullableIndexedWidgetBuilder separatorBuilder, }) { return SliverList( delegate: SliverChildBuilderDelegate( (context, index) { final itemIndex = index ~/ 2; return index.isEven ? itemBuilder(context, itemIndex) : separatorBuilder(context, itemIndex); }, childCount: math.max(0, itemCount * 2 - 1), ), ); } } class StickyFixedHeightHeaderDelegate extends SliverPersistentHeaderDelegate { const StickyFixedHeightHeaderDelegate({ required this.height, required this.child, }); final double height; final Widget child; @override double get minExtent => height; @override double get maxExtent => height; @override Widget build( BuildContext context, double shrinkOffset, bool overlapsContent, ) { return child; } @override bool shouldRebuild(StickyFixedHeightHeaderDelegate oldDelegate) { return height != oldDelegate.height; } } const Color darkBlue = Color.fromARGB(255, 18, 32, 47); void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( theme: ThemeData.dark().copyWith( scaffoldBackgroundColor: darkBlue, ), debugShowCheckedModeBanner: false, home: const Page(), ); } } class Page extends StatelessWidget { const Page({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Page'), ), body: CustomScrollView( slivers: [ SliverToBoxAdapter( child: Container( width: double.infinity, height: 300, color: Colors.red, )), SliverPersistentHeader( pinned: true, delegate: StickyFixedHeightHeaderDelegate( height: 200, child: Container( color: Colors.green, ),), ), SliverListEx.separated( itemCount: 100, itemBuilder: (_, index) => ListTile( key: ValueKey(index), title: Text('item: $index'), ), separatorBuilder: (_, __) => const Divider( color: Colors.blueGrey, ), ) ], ), ); } }