Reputation: 335
Background: I recently started development using flutter/dart, and as you can guess I came from iOS background. It was very easy to scroll in a UITableView to some given indexPath (section, row) in iOS, and I believe similar is the case in Android, but it has been a real pain to achieve the same in Flutter.
Questions: Can someone please point me to a solution where, in a ListView, I can scroll to a given index smoothly?
What I have tried: I have been trying different packages like (https://pub.dev/packages/flutter_section_table_view) because I needed a section-wise list view, it comes with an animate to section/row, but it depends on the accurate height of each row and creates a map to jump or animate the scroll view to that height value. It is not easy to achieve given that the items in that list view are dynamic and can expand or shrink depending on some actions. I tried to handle that as well by calculating heights and all that, but that was impacting the performance of scrolling. That is why I am looking for a solution with some precalculated map that can scroll to the tag or hash just like we have in web pages.
Upvotes: 1
Views: 258
Reputation: 54377
You can copy paste run full code below
You can use package https://pub.dev/packages/scroll_to_index
You can wrap widget
with AutoScrollTag
and call controller.scrollToIndex
code snippet
await controller.scrollToIndex(98,
preferPosition: AutoScrollPosition.begin);
...
Widget _wrapScrollTag({int index, Widget child}) => AutoScrollTag(
key: ValueKey(index),
controller: controller,
index: index,
child: child,
highlightColor: Colors.black.withOpacity(0.1),
);
working demo
full code
import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:scroll_to_index/scroll_to_index.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Scroll To Index Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Scroll To Index Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
static const maxCount = 10000;
final random = math.Random();
final scrollDirection = Axis.vertical;
AutoScrollController controller;
List<List<int>> randomList;
@override
void initState() {
super.initState();
controller = AutoScrollController(
viewportBoundaryGetter: () =>
Rect.fromLTRB(0, 0, 0, MediaQuery.of(context).padding.bottom),
axis: scrollDirection);
randomList = List.generate(maxCount,
(index) => <int>[index, (1000 * random.nextDouble()).toInt()]);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: ListView(
scrollDirection: scrollDirection,
controller: controller,
children: randomList.map<Widget>((data) {
return Padding(
padding: EdgeInsets.all(8),
child: _getRow(data[0], math.max(data[1].toDouble(), 50.0)),
);
}).toList(),
),
floatingActionButton: FloatingActionButton(
onPressed: _scrollToIndex,
tooltip: 'Increment',
child: Text(counter.toString()),
),
);
}
int counter = -1;
Future _scrollToIndex() async {
setState(() {
counter++;
if (counter >= maxCount) counter = 0;
});
//await controller.scrollToIndex(counter, preferPosition: AutoScrollPosition.begin);
await controller.scrollToIndex(98,
preferPosition: AutoScrollPosition.begin);
controller.highlight(counter);
}
Widget _getRow(int index, double height) {
return _wrapScrollTag(
index: index,
child: ListTile(title: Text('index: $index, height: $height')));
}
Widget _wrapScrollTag({int index, Widget child}) => AutoScrollTag(
key: ValueKey(index),
controller: controller,
index: index,
child: child,
highlightColor: Colors.black.withOpacity(0.1),
);
}
Upvotes: 1