Reputation: 1662
I have a PageView with 2 pages, I have a custom stack of navigator for each of both pages.
At the initial start(let's say I star on page 1), page 2 is built when I start scrolling or jump to it (as normal).
thought when I am on page 2 and go back to page 1 and vice-versa, the pages are kept alive and I would like to dispose/kill them to force a rebuild..at least on page 2.
I tried wantKeepAlive = false
but doesn't work.
can someone share a way to achieve that.
Upvotes: 1
Views: 4547
Reputation: 27990
If the goal is to tell our widgets to rebuild when pages are swiped back/forth, we can use the onPageChanged
callback of PageView.builder
.1
onPageChanged:
will run the function we give it each time a page is viewed.
onPageChanged
to Rebuild PagesThere's no built-in connection between onPageChanged
and rebuilding of pages in a PageView
.
onPageChanged
just runs any arbitrary function we give it, nothing more.
If we wish to rebuild pages with onPageChanged
we need to create that linkage ourselves.
ValueNotifier
/ValueListenableBuilder
In this example, we're using ValueNotifier
(the buildCount
variable) to notify the ValueListenableBuilder
to rebuild whenever buildCount
changes. (See Flutter Docs for info.)
Each time we swipe pages the buildCount
will increment and the ValueListenableBuilder
in our pages will rebuild, displaying the new total:
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
class PageViewRebuildPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('PageView Stream Rebuild'),
),
body: PageViewRebuildExample()
);
}
}
class PageViewRebuildExample extends StatelessWidget {
final List<String> contents = ['One', 'Two', 'Three'];
final ValueNotifier<int> buildCount = ValueNotifier<int>(0);
@override
Widget build(BuildContext context) {
print('Example built');
return Center(
child: PageView.builder(
itemCount: contents.length,
onPageChanged: (page) {
print('PageChanged $page');
buildCount.value++;
},
itemBuilder: (context, index) {
return Container(
alignment: Alignment.center,
margin: EdgeInsets.symmetric(vertical: 40, horizontal: 20),
color: Colors.lightBlueAccent,
child: ValueListenableBuilder(
valueListenable: buildCount,
// bldCnt here ↓↓ is buildCount.value
builder: (context, bldCnt, child) =>
// ↓ YOUR STUFF GOES HERE ↓
Text('Page ${contents[index]} : $bldCnt',
style: TextStyle(fontSize: 30)),
),
);
},
),
);
}
}
To adapt this example for your purposes, you'd replace the builder:
part of ValueListenableBuilder
with your Widget. It will be rebuilt on each swipe.
If you want to know the precise position of a page during a swipe gesture we can provide a PageController
to PageView
, attach a listener to that controller, and listen to the controller.page
output:
class PageViewRebuildExample extends StatefulWidget {
@override
_PageViewRebuildExampleState createState() => _PageViewRebuildExampleState();
}
// Switched to StatefulWidget so we can add listener & dispose
class _PageViewRebuildExampleState extends State<PageViewRebuildExample> {
final List<String> contents = ['One', 'Two', 'Three'];
final ValueNotifier<int> buildCount = ValueNotifier<int>(0);
final PageController controller = PageController(); // ← our new controller
@override
void initState() {
super.initState();
controller.addListener(() { // ← add a listener in onInit
print('Precise page position ${controller.page}');
});
}
@override
void dispose() {
controller.dispose(); // don't forget to dispose
super.dispose();
}
@override
Widget build(BuildContext context) {
print('Example built');
return Center(
child: PageView.builder(
itemCount: contents.length,
controller: controller, // ← PageController provided here
onPageChanged: (page) {
print('PageChanged $page');
buildCount.value++;
},
The output from our example listener above is (snipped to shorten):
I/flutter (14528): Precise page position 0.001861572265625
I/flutter (14528): Precise page position 0.006500244140625
I/flutter (14528): Precise page position 0.01019287109375
I/flutter (14528): Precise page position 0.012054443359375
... <snip>
I/flutter (14528): Precise page position 0.45981356897799835
I/flutter (14528): Precise page position 0.5179874247450384
I/flutter (14528): PageChanged 1
I/flutter (14528): Precise page position 0.5743095749455654
I/flutter (14528): Precise page position 0.6269737660740682
... <snip>
I/flutter (14528): Precise page position 0.9986377335325707
I/flutter (14528): Precise page position 0.9988375372072605
I/flutter (14528): Precise page position 0.9990080727700607
I/flutter (14528): Precise page position 1.0
1 There are likely many other ways to do this, this is just one method. For example, using Stream
to send events from onPageChanged
to a StreamBuilder
inside itemBuilder
is another.
Upvotes: 2