I like the InteractiveViewer solution by @DevQt it's perfect if you don't need to load in elements dynamically. But it doesn't use a package which I like and seems performant.
I'm just not sure how would you detect if you need to load in more elements. Maybe it's possible with it's controller.
I have found a package that has a scrollcontroller wich lets you detect if the user scrolled to the end.
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:single_child_two_dimensional_scroll_view/single_child_two_dimensional_scroll_view.dart';
void main() {
runApp(const MyApp());
}
class MyCustomScrollBehavior extends MaterialScrollBehavior {
@override
Set<PointerDeviceKind> get dragDevices => {
PointerDeviceKind.touch,
PointerDeviceKind.mouse,
};
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
scrollBehavior: MyCustomScrollBehavior(),
theme: ThemeData(primarySwatch: Colors.blue),
home: const HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('ListView example')),
body: SingleChildTwoDimensionalScrollView(
child: Column(
children: List.generate(
1000,
(index) => Container(
padding: const EdgeInsets.all(10),
color: index % 2 == 0 ? Colors.white : const Color(0xFFEFEFEF),
child: Text(
"$index very long long long long long long long long long"
"long long long long long long long long long long long"
"long long long long long long long long long long long"
"long long long long long long long long long long long"
"long long long long long long long long long long text",
softWrap: false,
),
),
),
),
),
);
}
}
You can also do it with two_dimensional_scrollables
, this can load infinite elements dinamycally, I'm just now sure how to get the SpanExtent to be the size of the Cell's content.
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:two_dimensional_scrollables/two_dimensional_scrollables.dart';
void main() {
runApp(const MyApp());
}
class MyCustomScrollBehavior extends MaterialScrollBehavior {
@override
Set<PointerDeviceKind> get dragDevices => {
PointerDeviceKind.touch,
PointerDeviceKind.mouse,
};
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
scrollBehavior: MyCustomScrollBehavior(),
theme: ThemeData(primarySwatch: Colors.blue),
home: const HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: TableView.builder(
cellBuilder: _buildCell,
columnCount: 1,
columnBuilder: _columnSpan,
rowCount: null,
rowBuilder: _rowSpan,
diagonalDragBehavior: DiagonalDragBehavior.free,
),
);
}
TableViewCell _buildCell(BuildContext context, TableVicinity vicinity) {
final Color boxColor = vicinity.row.isEven
? Colors.white
: Colors.indigo[100]!;
return TableViewCell(
child: ColoredBox(
color: boxColor,
child: Center(
child: Align(
alignment: Alignment.centerLeft,
child: Text(
"${vicinity.row} very long long long long long long long long long"
"long long long long long long long long long long long"
"long long long long long long long long long long long"
"long long long long long long long long long long long"
"long long long long long long long long long long text",
),
),
),
),
);
}
TableSpan _columnSpan(int index) {
return const TableSpan(extent: FixedTableSpanExtent(2000));
}
TableSpan _rowSpan(int index) {
return const TableSpan(extent: FixedTableSpanExtent(50));
}
}