Created
August 3, 2022 22:05
-
-
Save rohan20/0a89c207c8daabb0477897235a532156 to your computer and use it in GitHub Desktop.
LinkedScrollController Flutter example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const double _rankWidth = 50; | |
const double _teamInfoWidth = 90; | |
const double _ptsWidth = cellWidth; // cellWidth is 60 (from another file) | |
class _LeagueTable extends StatefulWidget { | |
final List<LeagueTableTeam> leagueTableTeams; | |
const _LeagueTable({required this.leagueTableTeams, Key? key}) : super(key: key); | |
@override | |
State<_LeagueTable> createState() => _LeagueTableState(); | |
} | |
class _LeagueTableState extends State<_LeagueTable> { | |
static const int _numberOfTeams = 20; | |
late final LinkedScrollControllerGroup horizontalScrollControllersGroup; | |
late final LinkedScrollControllerGroup verticalScrollControllersGroup; | |
// horizontal scroll controllers | |
late final ScrollController statHeadersHorizontalScrollController; | |
late final List<ScrollController> statValuesHorizontalScrollControllers; | |
// vertical scroll controllers | |
late final ScrollController teamInfoVerticalScrollController; | |
late final ScrollController teamStatsVerticalScrollController; | |
@override | |
void initState() { | |
super.initState(); | |
horizontalScrollControllersGroup = LinkedScrollControllerGroup(); | |
statHeadersHorizontalScrollController = horizontalScrollControllersGroup.addAndGet(); | |
statValuesHorizontalScrollControllers = []; | |
statValuesHorizontalScrollControllers.addAll( | |
List.generate(_numberOfTeams, (_) => horizontalScrollControllersGroup.addAndGet()), | |
); | |
verticalScrollControllersGroup = LinkedScrollControllerGroup(); | |
teamInfoVerticalScrollController = verticalScrollControllersGroup.addAndGet(); | |
teamStatsVerticalScrollController = verticalScrollControllersGroup.addAndGet(); | |
} | |
@override | |
void dispose() { | |
statHeadersHorizontalScrollController.dispose(); | |
for (final ScrollController controller in statValuesHorizontalScrollControllers) { | |
controller.dispose(); | |
} | |
teamInfoVerticalScrollController.dispose(); | |
teamStatsVerticalScrollController.dispose(); | |
super.dispose(); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return Column( | |
children: [ | |
_ColumnHeaders(scrollController: statHeadersHorizontalScrollController), | |
Expanded( | |
child: Row( | |
children: [ | |
// The fixed columns on the left | |
_TeamInfoColumns( | |
leagueTableTeams: widget.leagueTableTeams, | |
scrollController: teamInfoVerticalScrollController, | |
), | |
// The horizontally scrollable columns on the right | |
_StatValuesColumns( | |
leagueTableTeams: widget.leagueTableTeams, | |
scrollController: teamStatsVerticalScrollController, | |
statValuesHorizontalScrollControllers: statValuesHorizontalScrollControllers, | |
), | |
], | |
), | |
), | |
], | |
); | |
} | |
} | |
class _ColumnHeaders extends StatelessWidget { | |
final ScrollController scrollController; | |
const _ColumnHeaders({required this.scrollController}); | |
@override | |
Widget build(BuildContext context) { | |
return Container( | |
height: cellHeight, | |
child: Row( | |
children: [ | |
const FixedColumnHeaderCell("#", width: _rankWidth), | |
const FixedColumnHeaderCell("Team", width: _teamInfoWidth), | |
const FixedColumnHeaderCell("Pts", width: _ptsWidth), | |
Expanded( | |
child: ListView( | |
controller: scrollController, | |
physics: const ClampingScrollPhysics(), | |
scrollDirection: Axis.horizontal, | |
children: [ | |
const ColumnHeaderCell("P"), | |
const ColumnHeaderCell("W"), | |
const ColumnHeaderCell("D"), | |
const ColumnHeaderCell("L"), | |
const ColumnHeaderCell("GF"), | |
const ColumnHeaderCell("GA"), | |
const ColumnHeaderCell("GD"), | |
], | |
), | |
), | |
], | |
), | |
); | |
} | |
} | |
class _TeamInfoColumns extends StatelessWidget { | |
final List<LeagueTableTeam> leagueTableTeams; | |
final ScrollController scrollController; | |
const _TeamInfoColumns({required this.leagueTableTeams, required this.scrollController}); | |
@override | |
Widget build(BuildContext context) { | |
return Container( | |
width: _rankWidth + _teamInfoWidth + _ptsWidth, | |
child: ListView.builder( | |
controller: scrollController, | |
itemCount: leagueTableTeams.length, | |
itemBuilder: (_, index) { | |
final LeagueTableTeam leagueTableTeam = leagueTableTeams[index]; | |
return Row( | |
children: [ | |
ValueText("${index + 1}", width: _rankWidth, color: Colors.black54.withOpacity(0.1)), //rank | |
Container( | |
height: cellHeight, | |
width: _teamInfoWidth, | |
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 8), | |
decoration: BoxDecoration(border: Border.all(width: 1, color: ColorsDesignToken.neutral)), | |
child: Row( | |
children: [ | |
Expanded(flex: 1, child: TeamImage(teamId: leagueTableTeam.id)), | |
Expanded(flex: 2, child: CoreText.titleSm(leagueTableTeam.id.teamShortName, maxLines: 1)), | |
], | |
), | |
), | |
ValueText( | |
leagueTableTeam.points.toString(), | |
color: ColorsDesignToken.backgroundPrimary.withOpacity(0.1), | |
width: _ptsWidth, | |
), | |
], | |
); | |
}, | |
), | |
); | |
} | |
} | |
class _StatValuesColumns extends StatelessWidget { | |
final List<LeagueTableTeam> leagueTableTeams; | |
final ScrollController scrollController; | |
final List<ScrollController> statValuesHorizontalScrollControllers; | |
const _StatValuesColumns({ | |
required this.leagueTableTeams, | |
required this.scrollController, | |
required this.statValuesHorizontalScrollControllers, | |
}); | |
@override | |
Widget build(BuildContext context) { | |
return Expanded( | |
child: ListView.builder( | |
controller: scrollController, | |
itemCount: leagueTableTeams.length, | |
itemBuilder: (_, index) { | |
final LeagueTableTeam leagueTableTeam = leagueTableTeams[index]; | |
return SingleChildScrollView( | |
physics: const ClampingScrollPhysics(), | |
controller: statValuesHorizontalScrollControllers[index], | |
scrollDirection: Axis.horizontal, | |
child: Row( | |
children: [ | |
ValueText(leagueTableTeam.played.toString()), | |
ValueText(leagueTableTeam.wins.toString()), | |
ValueText(leagueTableTeam.draws.toString()), | |
ValueText(leagueTableTeam.loses.toString()), | |
ValueText(leagueTableTeam.goalsScored.toString()), | |
ValueText(leagueTableTeam.goalsConceded.toString()), | |
ValueText(leagueTableTeam.goalDifference.toString()), | |
], | |
), | |
); | |
}, | |
), | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
linked-scroll-controller.mp4