2

Do we have any event trigger when user enter the page.

I found Navigator.push().then(). But seen it's very unconvenient.

I want to have somethings like initState, but trigger every time user enter the page. In IONIC(hybrid frame work) its name is ionViewWillEnter

Thanks for your help!

Dung Hoang
  • 23
  • 5

1 Answers1

1

This is not really more convenient than Navigator.push().then() but you could use a RouteObserver to detect the page changes.

Code

For this example I am going to define 2 global variables:

final routeObserver = RouteObserver<ModalRoute<void>>();
int count = 0; // Number of times you are entering the page 

Then add routeObserver to your MaterialApp.navigatorObservers:

MaterialApp(
  home: InitialPage(),
  navigatorObservers: [routeObserver],
)

Finally, you will need to manage the subscription of your routeObserver to your page. For this you will have to use a StatefulWidget as your "enter on page" behavior will be defined thanks to the page's State:

class InitialPage extends StatefulWidget {
  @override
  State<InitialPage> createState() => _InitialPageState();
}

class _InitialPageState extends State<InitialPage> with RouteAware {
  @override
  void initState() {
    super.initState();
    count++;
  }
  
  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    routeObserver.subscribe(this, ModalRoute.of(context)!);
  }

  @override
  void dispose() {
    routeObserver.unsubscribe(this);
    super.dispose();
  }

  @override
  void didPopNext() {
    super.didPopNext();
    // view will appear
    setState(() => count++);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Text('You entered on this page $count times'),
            ElevatedButton(
              onPressed: () => Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (_) => OtherPage(),
                ),
              ),
              child: const Text('Press me'),
            ),
          ],
        ),
      ),
    );
  }
}

Basically what I am doing is incrementing the counter when instanciating the page thanks to initState (called when the page is added to the widget tree) and by registering the routeObserver to your view I will be able to increment my counter when my page is already in the widget tree with didPopNext (and using a setState to update my UI).

You can try the full example on DartPad

Guillaume Roux
  • 6,352
  • 1
  • 13
  • 38
  • Hi Guilaume Roux. This absolute is what i'm looking. But it's only work in the common case. With `Bottom navigation`, this widget alway on the top. So it alway trigger `didPopNext` on the nav bar class. Can we make it trigger on child tab? – Dung Hoang Sep 09 '21 at 03:52
  • I don't understand what you mean, this code also works if `InitialPage` is accessed from a BottomNavigationBar, here's a code sample you can try: https://dartpad.dev/?id=521018ad7a378640ee3da9169bf75d1f&null_safety=true – Guillaume Roux Sep 09 '21 at 07:41
  • You are right. It work with `BottomNavigationBar`. I used [persistent_bottom_nav_bar](https://pub.dev/packages/persistent_bottom_nav_bar), that my problem, it didn't trigger the `didPopNext ` function. I will raise this issue to that library. If you know, can you point me what problem with that library? – Dung Hoang Sep 09 '21 at 10:36
  • I've never used this package so I have no clue why it does not trigger the method. Maybe it uses another route observer which overrides the previous one. – Guillaume Roux Sep 09 '21 at 13:00
  • I known, it have their own navigatorObservers for each tab. – Dung Hoang Sep 20 '21 at 06:28