Как вызвать функцию void везде в моем приложении Flutter, используя InheritedWidget

У меня есть main.dart и кнопка в центре. Когда пользователь нажимает кнопку, он переходит на страницу home.dart. На моей странице home.dart также есть кнопка по центру, и когда пользователь нажимает кнопку, он переходит на страницу сведений. Дерево и код приложения показаны ниже.

Я пытаюсь реализовать "InheritedWidget" в моем home.dart, поэтому после того, как home.dart так глубоко, я могу вызвать функцию "void _handleUserInteraction" с помощью "InheritedWidget". К сожалению, я продолжаю получать сообщение об ошибке:

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

код home.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);
}

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,
        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',
                ),

              ],
            ),
          ),
        ));
  }
}

ОБНОВЛЕНИЕ: я изменяю свой код home.dart. OnTap: _callback работает, но в details.dart я получаю ту же ошибку, говоря, что:

ошибка: - Обратный вызов получателя был вызван на нуль.

1 ответ

Причина, по которой вы получаете ошибку 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, я предполагаю, что вы пытаетесь управлять состоянием. Если это так, вы можете проверить это руководство по внедрению управления состоянием приложения. Один из способов сделать это — использоватьprovider.

Вы можете попробовать запустить пример ниже. Я основывал его на данном образце.

основной дротик

      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 ++++++++");
  }
}

детали.дротик

      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',
                ),
              ],
            ),
          ),
        ));
      },
    );
  }
}

Другие вопросы по тегам