I'm trying to group my list items and create a sticky header for each group. Number of the items in each group may be different. So, I searched and found a package called sticky_headers 0.1.8+1. It is cool but it is creating header for each row. I can't find a way to group similar items under same header. This is my code;
class FixtureList extends StatelessWidget {
final dateFormat = DateFormat('MMMd');
final timeFormat = DateFormat('Hm');
@override
Widget build(BuildContext context) {
return Consumer<FixtureData>(
builder: (context, fixtureData, child) {
return ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemBuilder: (context, index) {
final fixture = fixtureData.fixtures[index];
return StickyHeader(
header: Container(
height: 30.0,
color: Colors.lightBlueAccent,
padding: EdgeInsets.symmetric(horizontal: 8.0),
alignment: Alignment.centerLeft,
child: Text(
dateFormat.format(fixture.dateTime.toLocal()),
style: const TextStyle(color: Colors.black),
),
),
content: FixtureTile(
date: dateFormat.format(fixture.dateTime.toLocal()),
time: timeFormat.format(fixture.dateTime.toLocal()),
homeTeam: fixture.homeTeam,
awayTeam: fixture.awayTeam,
homeOdds: fixture.homeOdds,
drawOdds: fixture.drawOdds,
awayOdds: fixture.awayOdds,
isHomeSelected: fixture.homeSelected,
isDrawSelected: fixture.drawSelected,
isAwaySelected: fixture.awaySelected,
homeCallBack: () =>
fixtureData.updateSelection(fixture, 'home'),
drawCallBack: () =>
fixtureData.updateSelection(fixture, 'draw'),
awayCallBack: () =>
fixtureData.updateSelection(fixture, 'away'),
),
);
},
itemCount: fixtureData.fixtures.length,
);
},
);
}
}
you could use the grouped_list package for this use case. It allows you to group your data by a custom criteria and it easy to use if you already use a ListView.
class FixtureList extends StatelessWidget {
final dateFormat = DateFormat('MMMd');
final timeFormat = DateFormat('Hm');
@override
Widget build(BuildContext context) {
return Consumer<FixtureData>(
builder: (context, fixtureData, child) {
return GroupedListView<FixtureData, string>(
scrollDirection: Axis.vertical,
shrinkWrap: true,
groupBy: (fixture) => // return the value by which the fixtures should be grouped,
groupSeparatorBuilder: (String groupByValue) {
// your widget for group headers here
},
itemBuilder: (context, fixture) {
// your widget for items here
},
elements: fixtureData.fixtures, // instead of itemCount here the list of objects is passed
);
},
);
}
}
Please check below example which uses flutter_sticky_header plugin.
import 'package:flutter/material.dart';
import 'package:flutter_sticky_header/flutter_sticky_header.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark()
.copyWith(scaffoldBackgroundColor: Color.fromARGB(255, 18, 32, 47)),
debugShowCheckedModeBanner: false,
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: ListExample()
);
}
}
class ListExample extends StatelessWidget {
const ListExample({
Key key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return AppScaffold(
title: 'List Example',
slivers: [
_StickyHeaderList(index: 0),
_StickyHeaderList(index: 1),
_StickyHeaderList(index: 2),
_StickyHeaderList(index: 3),
],
);
}
}
class _StickyHeaderList extends StatelessWidget {
const _StickyHeaderList({
Key key,
this.index,
}) : super(key: key);
final int index;
@override
Widget build(BuildContext context) {
return SliverStickyHeader(
header: Header(index: index),
sliver: SliverList(
delegate: SliverChildBuilderDelegate(
(context, i) =>
ListTile(
leading: CircleAvatar(
child: Text('$index'),
),
title: Text('List tile #$i'),
),
childCount: 6,
),
),
);
}
}
class Header extends StatelessWidget {
const Header({
Key key,
this.index,
this.title,
this.color = Colors.lightBlue,
}) : super(key: key);
final String title;
final int index;
final Color color;
@override
Widget build(BuildContext context) {
return Container(
height: 60,
color: color,
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
title ?? 'Header #$index',
style: const TextStyle(color: Colors.white),
),
);
}
}
class AppScaffold extends StatelessWidget {
const AppScaffold({
Key key,
@required this.title,
@required this.slivers,
this.reverse = false,
}) : super(key: key);
final String title;
final List<Widget> slivers;
final bool reverse;
@override
Widget build(BuildContext context) {
return DefaultStickyHeaderController(
child: Scaffold(
appBar: AppBar(
title: Text(title),
),
body: CustomScrollView(
slivers: slivers,
reverse: reverse,
),
),
);
}
}
You can create an array of slivers based on you conditions.

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