Как вызвать функцию 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',
),
],
),
),
));
},
);
}
}