How can I detect if a ListView item was added off-screen? I would like to scroll to the newly added item if it was added off-screen.
Below is a minimal example. If you keep pressing the + button, eventually an item will be added off-screen. I would like to detect that case and then scroll to the newly added item.
class _MyHomePageState extends State<MyHomePage> {
List<String> _items = [];
void _addItem() {
final count = _items.length + 1;
setState(() {
_items.add('Item $count');
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: ListView.builder(
itemCount: _items.length,
itemBuilder: (_, index) {
return Container(
height: 50,
child: Card(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Text(_items[index]),
],
),
),
);
}),
floatingActionButton: FloatingActionButton(
onPressed: _addItem,
tooltip: 'Add Item',
child: Icon(Icons.add),
),
);
}
}
https://dartpad.dev/81dcfd6e4255bde548751180c54a9ade
Check this. You need to use a scroll controller
Here is the code as the above Dartpad link is not working:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: MyHomePage()
),
);
}
}
class MyHomePage extends StatefulWidget {
@override
createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<String> _items = [];
// Add a scroll controller
ScrollController _scrollController = ScrollController();
void _addItem() {
final count = _items.length + 1;
setState(() {
_items.add('Item $count');
});
// Wait a frame for the new item to be built in your list view
WidgetsBinding.instance.addPostFrameCallback((duration) {
if(_scrollController.hasClients) {
// Move to the maxScrollExtent once the item has been added
_scrollController.animateTo(
_scrollController.position.maxScrollExtent,
curve: Curves.easeIn, // Use any curve you like
duration: const Duration(milliseconds: 200) // Set the anim duration
);
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Demo'),
),
body: ListView.builder(
controller: _scrollController, // Assign the controller
itemCount: _items.length,
itemBuilder: (_, index) {
return Container(
height: 50,
child: Card(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Text(_items[index]),
],
),
),
);
}),
floatingActionButton: FloatingActionButton(
onPressed: _addItem,
tooltip: 'Add Item',
child: Icon(Icons.add),
),
);
}
}