Skip to content

Instantly share code, notes, and snippets.

@diegoveloper
Created December 28, 2021 01:53
Show Gist options
  • Save diegoveloper/65bc470f062c31bb5186e9f9a8367d05 to your computer and use it in GitHub Desktop.
Save diegoveloper/65bc470f062c31bb5186e9f9a8367d05 to your computer and use it in GitHub Desktop.
class DiegoveloperDataTable extends StatefulWidget {
const DiegoveloperDataTable({Key? key}) : super(key: key);
@override
State<DiegoveloperDataTable> createState() => _DiegoveloperDataTableState();
}
const itemWidth = 120.0;
final itemsHeader = List.generate(
10, (index) => SizedBox(width: itemWidth, child: Text('Header $index')));
class _DiegoveloperDataTableState extends State<DiegoveloperDataTable> {
final _controllerHorizontalHeader = CustomScrollController();
final _controllerHorizontalBody = CustomScrollController();
void _listenScrollHeader() {
_controllerHorizontalBody.jumpToWithoutGoingIdleAndKeepingBallistic(
_controllerHorizontalHeader.offset);
}
void _listenScrollBody() {
_controllerHorizontalHeader.jumpToWithoutGoingIdleAndKeepingBallistic(
_controllerHorizontalBody.offset);
}
@override
void initState() {
_controllerHorizontalHeader.addListener(_listenScrollHeader);
_controllerHorizontalBody.addListener(_listenScrollBody);
super.initState();
}
@override
void dispose() {
_controllerHorizontalHeader.removeListener(_listenScrollHeader);
_controllerHorizontalBody.removeListener(_listenScrollBody);
_controllerHorizontalHeader.dispose();
_controllerHorizontalBody.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: [
const SliverToBoxAdapter(
child: Card(
child: Center(
child: FlutterLogo(
size: 300,
),
),
),
),
SliverAppBar(
title: SingleChildScrollView(
controller: _controllerHorizontalHeader,
scrollDirection: Axis.horizontal,
child: Row(
children: itemsHeader,
),
),
pinned: true,
),
SliverToBoxAdapter(
child: SingleChildScrollView(
controller: _controllerHorizontalBody,
scrollDirection: Axis.horizontal,
child: Column(
children: List.generate(
20,
(index) => Row(
children: List.generate(
itemsHeader.length,
(index) => SizedBox(
width: itemWidth,
child: ListTile(
title: Text('Item :$index'),
),
),
),
),
),
),
),
)
],
),
);
}
}
class CustomScrollController extends ScrollController {
CustomScrollController({
double initialScrollOffset = 0.0,
bool keepScrollOffset = true,
String? debugLabel,
}) : super(
initialScrollOffset: initialScrollOffset,
keepScrollOffset: keepScrollOffset,
debugLabel: debugLabel);
@override
_SilentScrollPosition createScrollPosition(
ScrollPhysics physics,
ScrollContext context,
ScrollPosition? oldPosition,
) {
return _SilentScrollPosition(
physics: physics,
context: context,
oldPosition: oldPosition,
initialPixels: initialScrollOffset,
);
}
void jumpToWithoutGoingIdleAndKeepingBallistic(double value) {
assert(positions.isNotEmpty, 'ScrollController not attached.');
for (_SilentScrollPosition position in List<ScrollPosition>.from(positions)
.whereType<_SilentScrollPosition>()) {
position.jumpToWithoutGoingIdleAndKeepingBallistic(value);
}
}
}
class _SilentScrollPosition extends ScrollPositionWithSingleContext {
_SilentScrollPosition({
required ScrollPhysics physics,
required ScrollContext context,
ScrollPosition? oldPosition,
double? initialPixels,
}) : super(
physics: physics,
context: context,
oldPosition: oldPosition,
initialPixels: initialPixels,
);
void jumpToWithoutGoingIdleAndKeepingBallistic(double value) {
if (pixels != value) {
forcePixels(value);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment