SliverMainAxisGroup and SliveTableView weird behavior with keyboard and scroll
I'm seeing some odd behavior with the keyboard and scroll position when using a SliverTableView inside a SliverMainAxisGroup that has more than one SliverToBoxAdapter.
As you can see in the attached video, when a TextField is tapped, the keyboard appears and then immediately hides, causing the list to scroll to the end.
https://github.com/user-attachments/assets/58203265-528c-4bcb-80a5-d406338e8776
Code to reproduce
import 'package:flutter/material.dart';
import 'package:material_table_view/material_table_view.dart';
import 'package:material_table_view/sliver_table_view.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Sliver Table Bug Demo',
theme: ThemeData(primarySwatch: Colors.blue, useMaterial3: true),
// --- CHOOSE WHICH PAGE TO DISPLAY ---
// home: BuggySliverTablePage(),
home: BuggySliverTablePage(),
);
}
}
class BuggySliverTablePage extends StatefulWidget {
const BuggySliverTablePage({super.key});
@override
State<BuggySliverTablePage> createState() => _BuggySliverTablePageState();
}
class _BuggySliverTablePageState extends State<BuggySliverTablePage> {
// Simple data for the table
final List<String> _items = List.generate(
50,
(index) => 'Item Row ${index + 1}',
);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Buggy Example'),
backgroundColor: Colors.red[400],
),
body: SafeArea(
child: Column(
children: [
Expanded(
child: CustomScrollView(
slivers: [
// This group introduces an extra layer that, when rebuilt,
// can cause the state of its children (the table) to be lost.
SliverMainAxisGroup(
slivers: [
SliverToBoxAdapter(
child: Container(
padding: const EdgeInsets.all(16),
color: Colors.red[50],
child: const Text(
'This is a header widget. When the keyboard appears, this section rebuilds, causing the SliverMainAxisGroup to be recreated, which in turn destroys and recreates the table below.',
textAlign: TextAlign.center,
),
),
),
SliverToBoxAdapter(
child: Container(
padding: const EdgeInsets.all(16),
color: Colors.red[50],
child: const Text(
'This is a header widget. When the keyboard appears, this section rebuilds, causing the SliverMainAxisGroup to be recreated, which in turn destroys and recreates the table below.',
textAlign: TextAlign.center,
),
),
),
SliverTableView.builder(
// ANTI-PATTERN: The 'columns' list is recreated on every build.
// When the parent rebuilds, Flutter sees a new list and
// destroys the old table state to build a new one.
columns: [
const TableColumn(width: 200),
const TableColumn(width: 200),
],
rowCount: _items.length,
rowHeight: 64,
rowBuilder: (context, row, contentBuilder) {
return contentBuilder(context, (context, column) {
if (column == 0) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Text(_items[row]),
);
} else {
return const Padding(
padding: EdgeInsets.all(8.0),
child: TextField(
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Enter value',
),
),
);
}
});
},
),
],
),
],
),
),
Container(
decoration: const BoxDecoration(
color: Colors.white,
border: Border(top: BorderSide(color: Colors.grey)),
),
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
child: const Text(
'Tap a text field above to show the keyboard. Notice how the table loses its state and scroll position when the keyboard appears.',
textAlign: TextAlign.center,
),
),
],
),
),
);
}
}
Good catch! It looks like the framework is trying to scroll to make a SliverTableView fit onto the screen resulting in scrolling to the very end and the originally clicked TextField closer to the top getting destroyed as it gets scrolled way off the screen.
I'll see if I can spare some time on investigating solutions to this problem. Let me know if I've missed anything.