如何从指向状态 class 函数的无状态 Widget 调用函数?
How to call a function from stateless Widget that points to state class function?
我正在尝试创建一个具有快速回复功能的响应式聊天机器人。我想在按下函数调用时创建一个按钮,调用另一个 class 的函数。我尝试使用回调。但我认为我做错了什么。请帮助我。
typedef void mycallback(String label);
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
@override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
User? user = FirebaseAuth.instance.currentUser;
UserModel loggedInUser = UserModel();
late DialogFlowtter dialogFlowtter;
final TextEditingController messageController = TextEditingController();
@override
void initState() {
super.initState();
DialogFlowtter.fromFile().then((instance) => dialogFlowtter = instance);
}
@override
Widget build(BuildContext context) {
var themeValue = MediaQuery.of(context).platformBrightness;
Body(
hi: sendMessage,
);
return Scaffold(
backgroundColor: themeValue == Brightness.dark
? HexColor('#262626')
: HexColor('#FFFFFF'),
appBar: AppBar(
//app bar ui
),
actions: [
//list if widget in appbar actions
PopupMenuButton(
icon: Icon(Icons.menu),
color: Colors.blue,
itemBuilder: (context) => [
PopupMenuItem<int>(
value: 0,
child: Text(
"Log out",
style: TextStyle(color: Colors.white),
),
),
],
onSelected: (item) => {logout(context)},
),
],
),
body: SafeArea(
child: Column(
children: [
Expanded(child: Body(messages: messages)),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 5,
),
child: Row(
children: [
Expanded(
child: TextFormField(
controller: messageController,
style: TextStyle(
color: themeValue == Brightness.dark
? Colors.white
: Colors.black,
fontFamily: 'Poppins'),
decoration: new InputDecoration(
enabledBorder: new OutlineInputBorder(
borderSide: new BorderSide(
color: themeValue == Brightness.dark
? Colors.white
: Colors.black),
borderRadius: BorderRadius.circular(15)),
hintStyle: TextStyle(
color: themeValue == Brightness.dark
? Colors.white54
: Colors.black54,
fontSize: 15,
fontStyle: FontStyle.italic,
),
labelStyle: TextStyle(
color: themeValue == Brightness.dark
? Colors.white
: Colors.black),
hintText: "Type here...",
),
),
),
IconButton(
color: themeValue == Brightness.dark
? Colors.white
: Colors.black,
icon: Icon(Icons.send),
onPressed: () {
sendMessage(messageController.text);
messageController.clear();
},
),
],
),
),
],
),
),
);
}
void sendMessage(String text) async {
if (text.isEmpty) return;
setState(() {
//do main function
});
}
}
class 我想调用函数的地方
class Body extends StatelessWidget {
final List<Map<String, dynamic>> messages;
final mycallback? hi;
const Body({
Key? key,
this.messages = const [],
this.buttons = const [],
this.hi,
this.onPressed,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return ListView.separated(
itemBuilder: (context, i) {
var obj = messages[messages.length - 1 - i];
Message message = obj['message'];
bool isUserMessage = obj['isUserMessage'] ?? false;
String label = obj['label'];
return Row(
mainAxisAlignment:
isUserMessage ? MainAxisAlignment.end : MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
_MessageContainer(
message: message,
isUserMessage: isUserMessage,
),
ElevatedButton(
child: Text(label),
onPressed: () => {hi ?? (label)},//This is where i want to call
style: ElevatedButton.styleFrom(
primary: Colors.blueAccent,
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 5),
textStyle: TextStyle(fontWeight: FontWeight.bold)),
),
],
);
},
separatorBuilder: (_, i) => Container(height: 10),
itemCount: messages.length,
reverse: true,
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 20,
),
);
}
}
代码运行没有错误,但当我按下按钮时没有任何反应。
这就是我实现类似功能的方式。您基本上是在小部件内要求一个 void 作为参数。几乎像 TextButton 或其他类似的小部件。
您也可以将其与两个有状态宽度一起使用,因为您是在将函数从一个借用到另一个。
此外,我认为提供程序会做得更好,因此我建议您研究一下。 (我没有足够的经验)
https://pub.dev/packages/provider
class MyHomePage extends StatefulWidget {
const MyHomePage({
Key? key,
}) : super(key: key);
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int x = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('An app'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('$x'),
TestWidget(onTap: () {
setState(() {
x++;
});
})
],
),
),
);
}
}
class TestWidget extends StatelessWidget {
final VoidCallback onTap;
const TestWidget({Key? key, required this.onTap}) : super(key: key);
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onTap,
child: Container(
padding: const EdgeInsets.all(20),
color: Colors.blue,
child: Text('test')),
);
}
}
我发现了错误。
在 class 主屏幕中,我错过了这一行。
child: Body(
messages: messages,
hi: (text) => {sendMessage(text)}, //this line
)
添加此行后,回调正常!
我正在尝试创建一个具有快速回复功能的响应式聊天机器人。我想在按下函数调用时创建一个按钮,调用另一个 class 的函数。我尝试使用回调。但我认为我做错了什么。请帮助我。
typedef void mycallback(String label);
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
@override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
User? user = FirebaseAuth.instance.currentUser;
UserModel loggedInUser = UserModel();
late DialogFlowtter dialogFlowtter;
final TextEditingController messageController = TextEditingController();
@override
void initState() {
super.initState();
DialogFlowtter.fromFile().then((instance) => dialogFlowtter = instance);
}
@override
Widget build(BuildContext context) {
var themeValue = MediaQuery.of(context).platformBrightness;
Body(
hi: sendMessage,
);
return Scaffold(
backgroundColor: themeValue == Brightness.dark
? HexColor('#262626')
: HexColor('#FFFFFF'),
appBar: AppBar(
//app bar ui
),
actions: [
//list if widget in appbar actions
PopupMenuButton(
icon: Icon(Icons.menu),
color: Colors.blue,
itemBuilder: (context) => [
PopupMenuItem<int>(
value: 0,
child: Text(
"Log out",
style: TextStyle(color: Colors.white),
),
),
],
onSelected: (item) => {logout(context)},
),
],
),
body: SafeArea(
child: Column(
children: [
Expanded(child: Body(messages: messages)),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 5,
),
child: Row(
children: [
Expanded(
child: TextFormField(
controller: messageController,
style: TextStyle(
color: themeValue == Brightness.dark
? Colors.white
: Colors.black,
fontFamily: 'Poppins'),
decoration: new InputDecoration(
enabledBorder: new OutlineInputBorder(
borderSide: new BorderSide(
color: themeValue == Brightness.dark
? Colors.white
: Colors.black),
borderRadius: BorderRadius.circular(15)),
hintStyle: TextStyle(
color: themeValue == Brightness.dark
? Colors.white54
: Colors.black54,
fontSize: 15,
fontStyle: FontStyle.italic,
),
labelStyle: TextStyle(
color: themeValue == Brightness.dark
? Colors.white
: Colors.black),
hintText: "Type here...",
),
),
),
IconButton(
color: themeValue == Brightness.dark
? Colors.white
: Colors.black,
icon: Icon(Icons.send),
onPressed: () {
sendMessage(messageController.text);
messageController.clear();
},
),
],
),
),
],
),
),
);
}
void sendMessage(String text) async {
if (text.isEmpty) return;
setState(() {
//do main function
});
}
}
class 我想调用函数的地方
class Body extends StatelessWidget {
final List<Map<String, dynamic>> messages;
final mycallback? hi;
const Body({
Key? key,
this.messages = const [],
this.buttons = const [],
this.hi,
this.onPressed,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return ListView.separated(
itemBuilder: (context, i) {
var obj = messages[messages.length - 1 - i];
Message message = obj['message'];
bool isUserMessage = obj['isUserMessage'] ?? false;
String label = obj['label'];
return Row(
mainAxisAlignment:
isUserMessage ? MainAxisAlignment.end : MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
_MessageContainer(
message: message,
isUserMessage: isUserMessage,
),
ElevatedButton(
child: Text(label),
onPressed: () => {hi ?? (label)},//This is where i want to call
style: ElevatedButton.styleFrom(
primary: Colors.blueAccent,
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 5),
textStyle: TextStyle(fontWeight: FontWeight.bold)),
),
],
);
},
separatorBuilder: (_, i) => Container(height: 10),
itemCount: messages.length,
reverse: true,
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 20,
),
);
}
}
代码运行没有错误,但当我按下按钮时没有任何反应。
这就是我实现类似功能的方式。您基本上是在小部件内要求一个 void 作为参数。几乎像 TextButton 或其他类似的小部件。
您也可以将其与两个有状态宽度一起使用,因为您是在将函数从一个借用到另一个。
此外,我认为提供程序会做得更好,因此我建议您研究一下。 (我没有足够的经验) https://pub.dev/packages/provider
class MyHomePage extends StatefulWidget {
const MyHomePage({
Key? key,
}) : super(key: key);
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int x = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('An app'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('$x'),
TestWidget(onTap: () {
setState(() {
x++;
});
})
],
),
),
);
}
}
class TestWidget extends StatelessWidget {
final VoidCallback onTap;
const TestWidget({Key? key, required this.onTap}) : super(key: key);
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onTap,
child: Container(
padding: const EdgeInsets.all(20),
color: Colors.blue,
child: Text('test')),
);
}
}
我发现了错误。 在 class 主屏幕中,我错过了这一行。
child: Body(
messages: messages,
hi: (text) => {sendMessage(text)}, //this line
)
添加此行后,回调正常!