(flutter) 将状态发送到其他小部件
(flutter) send state to other widget
在我的 Flutter 应用程序中,我想重新使用接收用户输入的自定义对话框。如果我在 class 中执行 showDialog()
并在另一个 class 中使用自定义 AlertDialog,则一切正常。但是,这迫使我每次都重新键入按钮的 onpressed 和 showdialog 部分。我更愿意将它也放在另一个可重用的 class 中并将用户输入传递给它(并在 return 中获得具有所有功能的按钮)。这样做的问题是加载页面时用户输入不存在,所以我需要知道按下按钮时的更新状态。在那里我卡住了......猜测它应该与传递小部件的状态有关,但在这里迷路了。
我创建了一个最小的应用程序来重现问题,这是代码:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: HomeScreen(),
);
}
}
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
@override
Widget build(BuildContext context) {
var myTextFieldController = TextEditingController();
return Scaffold(
appBar: AppBar(title: const Text('Dialog test')),
body: ListView(
padding: const EdgeInsets.all(20),
children: [
TextField(controller: myTextFieldController),
TestButton().getButton(context, myTextFieldController.text),
],
),
);
}
}
class TestButton {
Widget getButton(BuildContext context, myText) {
return ElevatedButton(
child: const Text('Show Dialog'),
onPressed: () {
showDialog(
context: context,
builder: (builder) {
return AlertDialog(
title: Text(myText), // is always empty
);
});
},
);
}
}
AlertDialog 的文本仍然为空,尽管 TextField 中有文本。我怎样才能让它工作?谢谢!
您可以按照以下步骤操作:
- 创建一个新的
String
变量来存储 TextField
中的值。
- 更新
TextField
的 onChanged 属性 中的 String
值并调用 setState。
- 将创建的新变量传递给
getButton
而不是 myTextFieldController.text
代码:
class _HomeScreenState extends State<HomeScreen> {
var myTextFieldController = TextEditingController();
String textValue = "";
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Dialog test')),
body: ListView(
padding: const EdgeInsets.all(20),
children: [
TextField(
controller: myTextFieldController,
onChanged: (v){
textValue = v;
setState((){});
}
),
TestButton().getButton(context, textValue),
],
),
);
}
为什么我用myTextFieldController.text时传递的值总是空的?
这是因为 myTextFieldController.text
的第一个值为 ""(空)的值是传递给 getButton
的值,并且在 getButton
TextField
个更改。
像这样调用您的 getbutton 方法.........
TestButton().getButton(context, myTextFieldController.value.text);
有效.....访问 textfieldcontroller 的 value 属性将解决此问题。
这是因为最初当您调用 TestButton().getButton
时,一个新的小部件是 built,初始值为 myTextFieldController.text
,它是空的。现在,当您插入文本时,myTextFieldController.text
的值会发生变化,但 flutter 仍在使用最初为 built 的小部件,因此对话框文本不会更新。强制 rebuild 的方法是在 myTextFieldController.text
更改时使用 setState
。但最好将小部件和对话框彼此分离。现在负责显示对话框的小部件是一个简单的 ElevatedButton
。如果它有一个相当复杂的 ui 需要在其他地方使用,那么最好实现一个新的小部件,而不是让 class 你在它的方法中使用一个小部件。如果您从 showDialog
中分离小部件,则不再需要调用 setState
。下面的代码有两个按钮来展示差异。第二个只是工作,第一个虽然你必须取消注释 TextField
:
的 onChanged
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
var myTextFieldController = TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Dialog test')),
body: ListView(
padding: const EdgeInsets.all(20),
children: [
TextField(
controller: myTextFieldController,
/// Uncomment the following 3 lines for the first button to work
// onChanged: (val) {
// // setState(() {});
// },
///
),
TestButton().getButton(context, myTextFieldController.text),
ElevatedButton(
onPressed: () => TestButton.showTestDialogue(context, myTextFieldController.text),
child: const Text('Show Test Dialog'),
),
],
),
);
}
}
class TestButton {
Widget getButton(BuildContext context, myText) {
return ElevatedButton(
child: const Text('Show Dialog'),
onPressed: () {
showDialog(
context: context,
builder: (builder) {
return AlertDialog(
title: Text(myText), // is always empty
);
},
);
},
);
}
static Future showTestDialogue(BuildContext context, myText) {
return showDialog(
context: context,
builder: (builder) {
return AlertDialog(
title: Text(myText),
);
},
);
}
}
在我的 Flutter 应用程序中,我想重新使用接收用户输入的自定义对话框。如果我在 class 中执行 showDialog()
并在另一个 class 中使用自定义 AlertDialog,则一切正常。但是,这迫使我每次都重新键入按钮的 onpressed 和 showdialog 部分。我更愿意将它也放在另一个可重用的 class 中并将用户输入传递给它(并在 return 中获得具有所有功能的按钮)。这样做的问题是加载页面时用户输入不存在,所以我需要知道按下按钮时的更新状态。在那里我卡住了......猜测它应该与传递小部件的状态有关,但在这里迷路了。
我创建了一个最小的应用程序来重现问题,这是代码:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: HomeScreen(),
);
}
}
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
@override
Widget build(BuildContext context) {
var myTextFieldController = TextEditingController();
return Scaffold(
appBar: AppBar(title: const Text('Dialog test')),
body: ListView(
padding: const EdgeInsets.all(20),
children: [
TextField(controller: myTextFieldController),
TestButton().getButton(context, myTextFieldController.text),
],
),
);
}
}
class TestButton {
Widget getButton(BuildContext context, myText) {
return ElevatedButton(
child: const Text('Show Dialog'),
onPressed: () {
showDialog(
context: context,
builder: (builder) {
return AlertDialog(
title: Text(myText), // is always empty
);
});
},
);
}
}
AlertDialog 的文本仍然为空,尽管 TextField 中有文本。我怎样才能让它工作?谢谢!
您可以按照以下步骤操作:
- 创建一个新的
String
变量来存储TextField
中的值。 - 更新
TextField
的 onChanged 属性 中的String
值并调用 setState。 - 将创建的新变量传递给
getButton
而不是myTextFieldController.text
代码:
class _HomeScreenState extends State<HomeScreen> {
var myTextFieldController = TextEditingController();
String textValue = "";
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Dialog test')),
body: ListView(
padding: const EdgeInsets.all(20),
children: [
TextField(
controller: myTextFieldController,
onChanged: (v){
textValue = v;
setState((){});
}
),
TestButton().getButton(context, textValue),
],
),
);
}
为什么我用myTextFieldController.text时传递的值总是空的?
这是因为 myTextFieldController.text
的第一个值为 ""(空)的值是传递给 getButton
的值,并且在 getButton
TextField
个更改。
像这样调用您的 getbutton 方法.........
TestButton().getButton(context, myTextFieldController.value.text);
有效.....访问 textfieldcontroller 的 value 属性将解决此问题。
这是因为最初当您调用 TestButton().getButton
时,一个新的小部件是 built,初始值为 myTextFieldController.text
,它是空的。现在,当您插入文本时,myTextFieldController.text
的值会发生变化,但 flutter 仍在使用最初为 built 的小部件,因此对话框文本不会更新。强制 rebuild 的方法是在 myTextFieldController.text
更改时使用 setState
。但最好将小部件和对话框彼此分离。现在负责显示对话框的小部件是一个简单的 ElevatedButton
。如果它有一个相当复杂的 ui 需要在其他地方使用,那么最好实现一个新的小部件,而不是让 class 你在它的方法中使用一个小部件。如果您从 showDialog
中分离小部件,则不再需要调用 setState
。下面的代码有两个按钮来展示差异。第二个只是工作,第一个虽然你必须取消注释 TextField
:
onChanged
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
var myTextFieldController = TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Dialog test')),
body: ListView(
padding: const EdgeInsets.all(20),
children: [
TextField(
controller: myTextFieldController,
/// Uncomment the following 3 lines for the first button to work
// onChanged: (val) {
// // setState(() {});
// },
///
),
TestButton().getButton(context, myTextFieldController.text),
ElevatedButton(
onPressed: () => TestButton.showTestDialogue(context, myTextFieldController.text),
child: const Text('Show Test Dialog'),
),
],
),
);
}
}
class TestButton {
Widget getButton(BuildContext context, myText) {
return ElevatedButton(
child: const Text('Show Dialog'),
onPressed: () {
showDialog(
context: context,
builder: (builder) {
return AlertDialog(
title: Text(myText), // is always empty
);
},
);
},
);
}
static Future showTestDialogue(BuildContext context, myText) {
return showDialog(
context: context,
builder: (builder) {
return AlertDialog(
title: Text(myText),
);
},
);
}
}