How to call a void function everywhere in my Flutter app using InheritedWidget?

8,826 views
Skip to first unread message

Niyazi Toros

unread,
Nov 24, 2018, 8:54:26 AM11/24/18
to Flutter Dev
How to call a void function everywhere in my Flutter app using InheritedWidget?

I have a main.dart and has a button in center. When user tabs the button it navigate into home.dart page. My home.dart page also has a button on center and when user tabs the button it navigate to details page. The app tree and code is shown below.

I try to implement the "InheritedWidget" in my home.dart so after the home.dart as deep as I go I can call the "void _handleUserInteraction" function using "InheritedWidget". Unluckly I am keep getting error that says:


I/flutter (20715): The getter 'handleOnTap' was called on null.

I/flutter (20715): Receiver: null

I/flutter (20715): Tried calling: handleOnTap



home.dart code:

import 'package:flutter/material.dart';

import 'dart:async';

import 'main.dart';

import 'details.dart';


class MyHomePage extends StatefulWidget {

  @override

  _MyHomePageState createState() => _MyHomePageState();

}


class _MyHomePageState extends State<MyHomePage> {

  Timer timer;


  // TODO: 1 - INIT STATE

  @override

  void initState() {

    super.initState();

    setState(() {

      _initializeTimer();

    });

  }


  // TODO: 3 - INITIALIZE TIMER

  void _initializeTimer() {

    timer = Timer.periodic(const Duration(minutes: 5), (__) {

      _logOutUser();

    });

  }


  // TODO: 4 - LOG OUT USER

  void _logOutUser() {

    timer.cancel();


    Navigator.push(

        context, new MaterialPageRoute(builder: (context) => new MyApp()));

  }


  // TODO: 5 - HANDLE USER INTERACTION

  // void _handleUserInteraction([_]) {

  void _handleUserInteraction() {

    print("+++++++ _handleUserInteraction Header ++++++++");

    if (!timer.isActive) {

      return;

    }

    timer.cancel();

    _initializeTimer();

    print("+++++++ _handleUserInteraction Footer ++++++++");

  }


  @override

  Widget build(BuildContext context) {

    return LoginState(

        handleOnTap: _handleUserInteraction,

        child: GestureDetector(

            onTap: _handleUserInteraction,

            onDoubleTap: _handleUserInteraction,

            onLongPress: _handleUserInteraction,

            onTapCancel: _handleUserInteraction,

            child: new Scaffold(

              appBar: AppBar(

                title: Text("HOME PAGE"),

              ),

              body: Center(

                child: Column(

                  mainAxisAlignment: MainAxisAlignment.center,

                  children: <Widget>[

                    Text(

                      'GOTO DETAILS PAGE',

                    ),

                    new RaisedButton(

                        child: new Text("Details"),

                        onPressed: () {

                          Navigator.push(

                              context,

                              new MaterialPageRoute(

                                  builder: (context) => new Details()));

                        })

                  ],

                ),

              ),

            )));

  }

}



class LoginState extends InheritedWidget {

  LoginState({

    Key key,

    @required Widget child,

    @required this.handleOnTap,

  }): super(key: key, child: child);


  final VoidCallback handleOnTap;


  static LoginState of(BuildContext context) {

    return context.inheritFromWidgetOfExactType(LoginState);

  }


  @override

  bool updateShouldNotify(LoginState oldWidget) => true;

}



details.dart code:

import 'package:flutter/material.dart';

import 'home.dart';


class Details extends StatefulWidget {

  @override

  _DetailsState createState() => _DetailsState();

}


class _DetailsState extends State<Details> {

  @override

  Widget build(BuildContext context) {

    return GestureDetector(

        onTap: LoginState.of(context).handleOnTap,

        onDoubleTap: LoginState.of(context).handleOnTap,

        onLongPress: LoginState.of(context).handleOnTap,

        onTapCancel: LoginState.of(context).handleOnTap,

        child: new Scaffold(

          appBar: AppBar(

            title: Text("Details PAGE"),

          ),

          body: Center(

            child: Column(

              mainAxisAlignment: MainAxisAlignment.center,

              children: <Widget>[

                Text(

                  'Every time Tabed it reset the home timer',

                ),


              ],

            ),

          ),

        ));

  }

}

Ian Hickson

unread,
Nov 24, 2018, 4:31:02 PM11/24/18
to Niyazi Toros, Flutter Dev
The Details and the MyHomePage are both descendants of your Navigator, but your inherited widget is only in the MyHomePage. Notably, the inherited widget is not an ancestor of the Details. So when the Details looks up the inherited widget, it doesn't find it.

Put the inherited widget above your MaterialApp/CupertinoApp/WidgetsApp or Navigator and it should work.

PS: Since LoginState has no actual state, updateShouldNotify can return false.

--
You received this message because you are subscribed to the Google Groups "Flutter Dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to flutter-dev...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
--

--
Ian Hickson

😸

Niyazi Toros

unread,
Nov 25, 2018, 12:48:09 AM11/25/18
to Flutter Dev
Thanks Ian, I don't want to use my timer in main.dart. I need to use my timer in home.dart and rest of the tree. So I change my home.dart and the details.dart. The onTap: _callback, is working in home.dart but getting same error on details.dart. In my home.dart I created new MaterialApp. Any idea?


home.dart
  Widget build(BuildContext context) => MaterialApp(
theme: ThemeData(
primarySwatch: Colors.red,
),
home: LoginState(
callback: _handleUserInteraction,
child: Builder(builder: homeScreenBuilder)),
);
}

@override
Widget homeScreenBuilder(BuildContext context) {
Function() _callback = LoginState.of(context).callback;
return GestureDetector(
onTap: _callback,
onDoubleTap: _callback,
onLongPress: _callback,
onTapCancel: _callback,

child: new Scaffold(
appBar: AppBar(
title: Text("HOME PAGE"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'GOTO DETAILS PAGE',
),
new RaisedButton(
child: new Text("Details"),
onPressed: () {
Navigator.push(
context,
new MaterialPageRoute(
builder: (context) => new Details()));
})
],
),
),
      ));
}

class LoginState extends InheritedWidget {
final Widget child;
final Function() callback;
final Key key;

LoginState({@required this.callback, @required this.child, this.key})
: super(key: key);

@override
bool updateShouldNotify(LoginState oldWidget) {
return true;
}

static LoginState of(BuildContext context) =>
context.inheritFromWidgetOfExactType(LoginState);
}



details.dart 

import 'package:flutter/material.dart';
import 'home.dart';

class Details extends StatefulWidget {
@override
_DetailsState createState() => _DetailsState();
}

class _DetailsState extends State<Details> {
@override
Widget build(BuildContext context) {
    Function() _callback = LoginState.of(context).callback;
return GestureDetector(
onTap: _callback,
onDoubleTap: _callback,
onLongPress: _callback,
onTapCancel: _callback,

Benedicte Roussel

unread,
Nov 25, 2018, 5:15:21 AM11/25/18
to niyazi...@gmail.com, Flutter Dev
your Detail class does not know where to go up in the tree, it is the role of an inheritedFromWidgetOfExactType method to do so.


Le dim., nov. 25, 2018 à 6:48, Niyazi Toros
<niyazi...@gmail.com> a écrit :
--

Niyazi Toros

unread,
Nov 25, 2018, 5:43:58 AM11/25/18
to Flutter Dev
@Bened I thought the "LoginState.of(context).handleOnTap," sufficient enough to goto inherited widget. Is it possible to give me more detail information regarding to my example?

Benedicte Roussel

unread,
Nov 25, 2018, 8:36:59 AM11/25/18
to niyazi...@gmail.com, Flutter Dev

hum, I have not enough knowledge of inherited widget but here in your code I think you go too quick. LoginState must be reach first and then it's function used. But my beginner level can not help you further :) sorry about that and may be I am wrong.... but I understand that any class under the tree can inherited from your widget but it is not automatic. Something must state it clearly.... something like final  loginState=LoginState.of(context);
Widget build(BuildContext context) {
Function() _callback = LoginState.of(context).callback;
Le dim., nov. 25, 2018 à 11:44, Niyazi Toros
<niyazi...@gmail.com> a écrit :
@Bened I thought the "LoginState.of(context). handleOnTap," sufficient enough to goto inherited widget. Is it possible to give me more detail information regarding to my example?

Niyazi Toros

unread,
Nov 26, 2018, 4:24:05 AM11/26/18
to Flutter Dev
Well, I mange to make it work. If anyone things there is a better method please feel free to post your view.

Reply all
Reply to author
Forward
0 new messages