I have a very simple Flutter app with a TabBarView with two views (Tab 1 and Tab 2), one of them (Tab 1) has
If you give each TabBarView a PageStorageKey the scroll offset will be saved. See more info about PageStorageKey here.
Output:
Code:
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
title: Text("PageStorageKey"),
bottom: TabBar(
tabs: [
Tab(icon: Icon(Icons.looks_one), text: "List1"),
Tab(icon: Icon(Icons.looks_two), text: "List2"),
],
),
),
body: TabBarView(
children: [
_buildList(key: "key1", string: "List1: "),
_buildList(key: "key2", string: "List2: "),
],
),
),
);
}
Widget _buildList({String key, String string}) {
return ListView.builder(
key: PageStorageKey(key),
itemBuilder: (_, i) => ListTile(title: Text("${string} ${i}")),
);
}
Is there a way to execute Widget build(BuildContext context) method only once...
Imho, idea of flutter is to be ready for rebuilding always. It should be cheap. If you have some expensive actions, you can use State to "cache" results. E.g. you can do network request in initState
and via setState
rebuild when receive response. For tabs, you can prepare and save data in parent widget. You can find more info in flutter tutorial about managing state
To be more specific, you can use PageStorageKey with any scrollable view to keep the scrolling position, e.g.:
new ListView.builder(key: new PageStorageKey('myListView'), ...)
Can't add a comment, so left it as answer.
If you using PageStorageKey
, have a lot of items in the ListView
, scroll down plenty items and have lag on tab switch, the solution is to provide itemExtent
to ListView
.
As I understand, without itemExtent
ListView
don't know which items immediately show, because using PageStorageKey
cashed only position in pixels, and ListView
need calculate height of all items scrolled from top. In another hand, with itemExtent
ListView
can easily calculate item to show, for example: index = cashedPositionInPixels / itemExtent
.