如何从一个 statefulWidget 调用另一个 Widget (Flutter) 中的方法
How to call a method from one statefulWidget in another Widget (Flutter)
我正在尝试通过单击 FloatingActionButton
从另一个小部件 运行 方法 doAnimation
。
请告诉我如何用这个简单的例子来做到这一点。我知道如何使用 Provider 包来做到这一点,但代码很麻烦。我如何使用 Flutter 的本地方法来做到这一点?
或者,最有可能的是,它可以通过 Provider 很好地完成,但我不知道该怎么做。
已经有人问过类似的问题,但是 flutter 和 dart 的第二个版本已经发布了。
状态管理困难可能是新手最大的问题。
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key}) : super(key: key);
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: MyAnimation(),
floatingActionButton: FloatingActionButton(
onPressed: () {
//TODO! error is here
_MyAnimationState().doAnimation();
//MyAnimation().createState().doAnimation(); // ?
},
child: Icon(Icons.play_arrow),
),
);
}
}
class MyAnimation extends StatefulWidget {
const MyAnimation({Key? key}) : super(key: key);
@override
_MyAnimationState createState() => _MyAnimationState();
}
class _MyAnimationState extends State<MyAnimation> {
double _height = 250;
bool _isOpen = true;
void doAnimation() {
_isOpen = !_isOpen;
setState(() {
if (_isOpen) {
_height = 250;
} else {
_height = 0;
}
});
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: AnimatedContainer(
padding: EdgeInsets.all(20),
duration: Duration(milliseconds: 250),
width: 250,
height: _height,
color: Colors.lightBlueAccent,
child: Center(
child: Text(
'My Test String',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 35, fontWeight: FontWeight.bold),
),
),
),
),
ElevatedButton(
onPressed: () {
doAnimation(); // works as it should
},
child: (_isOpen)? Text('Close Widget') : Text('Open Widget'))
],
);
}
}
当我尝试以通常方式使用 class 方法时出现此错误。
This happens when you call setState() on a State object for a widget that hasn't been inserted into the widget tree yet. It is not necessary to call setState() in the constructor, since the state is already assumed to be dirty when it is initially created.
您可以尝试在 initState() 中编写“doAnimation()”,而不是使用 floatingActionButton,以便在初始化小部件时触发此操作。
double _height;
bool _isOpen;
@override
void initState() {
super.initState();
bool _isOpen = true;
if (_isOpen) {
_height = 250;
} else {
_height = 0;
}
}
然后使用 ElevatedButton 作为 bool 和 setState 的 setter 来重新渲染小部件:
ElevatedButton(
onPressed: () {
setState(() {
_isOpen = !_isOpen;
if (_isOpen) {
_height = 250;
} else {
_height = 0;
}
});
},
child: (_isOpen)? Text('Close Widget') : Text('Open Widget'))
],
);
您的代码将如下所示:
class MyAnimation extends StatefulWidget {
@override
_MyAnimationState createState() => _MyAnimationState();
}
class _MyAnimationState extends State<MyAnimation> {
double _height;
bool _isOpen;
@override
void initState() {
super.initState();
bool _isOpen = true;
if (_isOpen) {
_height = 250;
} else {
_height = 0;
}
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: AnimatedContainer(
padding: EdgeInsets.all(20),
duration: Duration(milliseconds: 250),
width: 250,
height: _height,
color: Colors.lightBlueAccent,
child: Center(
child: Text(
'My Test String',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 35, fontWeight: FontWeight.bold),
),
),
),
),
ElevatedButton(
onPressed: () {
setState(() {
_isOpen = !_isOpen;
if (_isOpen) {
_height = 250;
} else {
_height = 0;
}
});
},
child: (_isOpen)? Text('Close Widget') : Text('Open Widget'))
],
);
}
}
您还可以使用 Provider 通过 setter 函数设置 _isOpen 值并避免对小部件按钮进行所有这些验证。
这其实很简单,不需要任何包。您可以在全局键的帮助下执行此操作。首先像这样 GlobalKey<_MyAnimationState> _key = GlobalKey<_MyAnimationState>();
创建一个全局密钥。然后像这样 MyAnimation(key: _key)
使用 MyAnimation class 时传递此键。现在在 onPressed 函数中使用这个键来调用 doAnimation 方法,像这样 _key.currentState!.doAnimation();
这是完整的实现。
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key}) : super(key: key);
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
GlobalKey<_MyAnimationState> _key = GlobalKey<_MyAnimationState>(); // declaration of the key
@override
Widget build(BuildContext context) {
return Scaffold(
body: MyAnimation(key: _key), // passing the key
floatingActionButton: FloatingActionButton(
onPressed: () {
_key.currentState!.doAnimation(); // calling the method from child widget
},
child: Icon(Icons.play_arrow),
),
);
}
}
class MyAnimation extends StatefulWidget {
const MyAnimation({Key? key}) : super(key: key);
@override
_MyAnimationState createState() => _MyAnimationState();
}
class _MyAnimationState extends State<MyAnimation> {
double _height = 250;
bool _isOpen = true;
void doAnimation() {
_isOpen = !_isOpen;
setState(() {
if (_isOpen) {
_height = 250;
} else {
_height = 0;
}
});
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: AnimatedContainer(
padding: EdgeInsets.all(20),
duration: Duration(milliseconds: 250),
width: 250,
height: _height,
color: Colors.lightBlueAccent,
child: Center(
child: Text(
'My Test String',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 35, fontWeight: FontWeight.bold),
),
),
),
),
ElevatedButton(
onPressed: () {
doAnimation(); // works as it should
},
child: (_isOpen)? Text('Close Widget') : Text('Open Widget'))
],
);
}
}
我正在尝试通过单击 FloatingActionButton
从另一个小部件 运行 方法 doAnimation
。
请告诉我如何用这个简单的例子来做到这一点。我知道如何使用 Provider 包来做到这一点,但代码很麻烦。我如何使用 Flutter 的本地方法来做到这一点?
或者,最有可能的是,它可以通过 Provider 很好地完成,但我不知道该怎么做。
已经有人问过类似的问题,但是 flutter 和 dart 的第二个版本已经发布了。
状态管理困难可能是新手最大的问题。
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key}) : super(key: key);
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: MyAnimation(),
floatingActionButton: FloatingActionButton(
onPressed: () {
//TODO! error is here
_MyAnimationState().doAnimation();
//MyAnimation().createState().doAnimation(); // ?
},
child: Icon(Icons.play_arrow),
),
);
}
}
class MyAnimation extends StatefulWidget {
const MyAnimation({Key? key}) : super(key: key);
@override
_MyAnimationState createState() => _MyAnimationState();
}
class _MyAnimationState extends State<MyAnimation> {
double _height = 250;
bool _isOpen = true;
void doAnimation() {
_isOpen = !_isOpen;
setState(() {
if (_isOpen) {
_height = 250;
} else {
_height = 0;
}
});
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: AnimatedContainer(
padding: EdgeInsets.all(20),
duration: Duration(milliseconds: 250),
width: 250,
height: _height,
color: Colors.lightBlueAccent,
child: Center(
child: Text(
'My Test String',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 35, fontWeight: FontWeight.bold),
),
),
),
),
ElevatedButton(
onPressed: () {
doAnimation(); // works as it should
},
child: (_isOpen)? Text('Close Widget') : Text('Open Widget'))
],
);
}
}
当我尝试以通常方式使用 class 方法时出现此错误。
This happens when you call setState() on a State object for a widget that hasn't been inserted into the widget tree yet. It is not necessary to call setState() in the constructor, since the state is already assumed to be dirty when it is initially created.
您可以尝试在 initState() 中编写“doAnimation()”,而不是使用 floatingActionButton,以便在初始化小部件时触发此操作。
double _height;
bool _isOpen;
@override
void initState() {
super.initState();
bool _isOpen = true;
if (_isOpen) {
_height = 250;
} else {
_height = 0;
}
}
然后使用 ElevatedButton 作为 bool 和 setState 的 setter 来重新渲染小部件:
ElevatedButton(
onPressed: () {
setState(() {
_isOpen = !_isOpen;
if (_isOpen) {
_height = 250;
} else {
_height = 0;
}
});
},
child: (_isOpen)? Text('Close Widget') : Text('Open Widget'))
],
);
您的代码将如下所示:
class MyAnimation extends StatefulWidget {
@override
_MyAnimationState createState() => _MyAnimationState();
}
class _MyAnimationState extends State<MyAnimation> {
double _height;
bool _isOpen;
@override
void initState() {
super.initState();
bool _isOpen = true;
if (_isOpen) {
_height = 250;
} else {
_height = 0;
}
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: AnimatedContainer(
padding: EdgeInsets.all(20),
duration: Duration(milliseconds: 250),
width: 250,
height: _height,
color: Colors.lightBlueAccent,
child: Center(
child: Text(
'My Test String',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 35, fontWeight: FontWeight.bold),
),
),
),
),
ElevatedButton(
onPressed: () {
setState(() {
_isOpen = !_isOpen;
if (_isOpen) {
_height = 250;
} else {
_height = 0;
}
});
},
child: (_isOpen)? Text('Close Widget') : Text('Open Widget'))
],
);
}
}
您还可以使用 Provider 通过 setter 函数设置 _isOpen 值并避免对小部件按钮进行所有这些验证。
这其实很简单,不需要任何包。您可以在全局键的帮助下执行此操作。首先像这样 GlobalKey<_MyAnimationState> _key = GlobalKey<_MyAnimationState>();
创建一个全局密钥。然后像这样 MyAnimation(key: _key)
使用 MyAnimation class 时传递此键。现在在 onPressed 函数中使用这个键来调用 doAnimation 方法,像这样 _key.currentState!.doAnimation();
这是完整的实现。
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key}) : super(key: key);
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
GlobalKey<_MyAnimationState> _key = GlobalKey<_MyAnimationState>(); // declaration of the key
@override
Widget build(BuildContext context) {
return Scaffold(
body: MyAnimation(key: _key), // passing the key
floatingActionButton: FloatingActionButton(
onPressed: () {
_key.currentState!.doAnimation(); // calling the method from child widget
},
child: Icon(Icons.play_arrow),
),
);
}
}
class MyAnimation extends StatefulWidget {
const MyAnimation({Key? key}) : super(key: key);
@override
_MyAnimationState createState() => _MyAnimationState();
}
class _MyAnimationState extends State<MyAnimation> {
double _height = 250;
bool _isOpen = true;
void doAnimation() {
_isOpen = !_isOpen;
setState(() {
if (_isOpen) {
_height = 250;
} else {
_height = 0;
}
});
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: AnimatedContainer(
padding: EdgeInsets.all(20),
duration: Duration(milliseconds: 250),
width: 250,
height: _height,
color: Colors.lightBlueAccent,
child: Center(
child: Text(
'My Test String',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 35, fontWeight: FontWeight.bold),
),
),
),
),
ElevatedButton(
onPressed: () {
doAnimation(); // works as it should
},
child: (_isOpen)? Text('Close Widget') : Text('Open Widget'))
],
);
}
}