如何使用InheritedWidget在我的Flutter应用中的任何地方调用void函数

时间:2018-11-24 09:42:25

标签: flutter inherited-widget

我有一个main.dart,中间有一个按钮。当用户点击按钮时,它将导航到home.dart页面。我的home.dart页面的中心还有一个按钮,当用户单击该按钮时,它会导航到详细信息页面。应用程序树和代码如下所示。

我尝试在home.dart中实现“ InheritedWidget” ,因此在home.dart之后,我可以调用“ void _handleUserInteraction” 函数使用“ InheritedWidget”。不幸的是,我不断收到错误消息:

dependencies {
    classpath 'com.android.tools.build:gradle:3.2.0'
    classpath 'com.google.ar.sceneform:plugin:1.6.0'
}

home.dart代码:

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

details.dart代码:

    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) => 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);
}

更新: 我更改了home.dart代码。 onTap:_callback正常运行,但在details.dart中,我得到了同样的错误:

错误:-调用getter的“回调”为null。

1 个答案:

答案 0 :(得分:0)

您收到错误 The getter 'callback' was called on null. 的原因是因为 LoginState.of(context) 为空。

class _DetailsState extends State<Details> {
  @override
  Widget build(BuildContext context) {
    Function() _callback = LoginState.of(context).callback;
    ...
  }
}

由于您正在使用 InheritedWidget,我假设您可能正在尝试进行状态管理。如果是这样,您可以查看有关实施应用状态管理的 guide。一种方法是使用 provider

您可以尝试运行下面的示例。我是根据给定的样本得出的。

main.dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'dart:async';
import 'details.dart';

void main() {
  // https://flutter.dev/docs/development/data-and-backend/state-mgmt/simple#changenotifierprovider
  runApp(ChangeNotifierProvider(
    create: (context) => LoginState(),
    child: MyApp(),
  ));
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  void initState() {
    super.initState();
    // This allows access to LoginState data if no UI changes needed
    // https://flutter.dev/docs/development/data-and-backend/state-mgmt/simple#providerof
    Provider.of<LoginState>(context, listen: false).initializeTimer();
  }

  @override
  Widget build(BuildContext context) {
    // Consumer grants access to LoginState
    // https://flutter.dev/docs/development/data-and-backend/state-mgmt/simple#consumer
    return Consumer<LoginState>(
      builder: (context, loginState, child) {
        return GestureDetector(
            onTap: () => loginState.handleUserInteraction(),
            // 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()));
                    })
              ],
            ),
          ),
        ));
      },
    );
  }
}

// https://flutter.dev/docs/development/data-and-backend/state-mgmt/simple#changenotifier
class LoginState extends ChangeNotifier {
  Timer _timer;

  void initializeTimer() {
    _timer = Timer.periodic(const Duration(minutes: 5), (__) {
      logOutUser();
    });
  }

  void logOutUser() {
    _timer.cancel();
  }

  void handleUserInteraction() {
    print("+++++++ _handleUserInteraction Header ++++++++");
    if (!_timer.isActive) {
      return;
    }
    _timer.cancel();
    initializeTimer();
    print("+++++++ _handleUserInteraction Footer ++++++++");
  }
}

详细信息.dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'main.dart';

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

class _DetailsState extends State<Details> {
  @override
  Widget build(BuildContext context) {
    return Consumer<LoginState>(
      builder: (context, loginState, child) {
        return GestureDetector(
            onTap: () => loginState.handleUserInteraction(),
            // onDoubleTap: _callback,
            // onLongPress: _callback,
            // onTapCancel: _callback,
            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',
                ),
              ],
            ),
          ),
        ));
      },
    );
  }
}