我的 TextField 小部件遇到问题。每次用户点击它们时,整个小部件都会重新加载,并且键盘会消失。我相信我将问题追溯到主要检查用户身份验证的流构建器。这是我的 main.dart 中 MyApp 小部件的摘要版本:
class MyApp extends StatelessWidget {
const MyApp({super.key});
// this widget is the root of your application.
@override
Widget build(BuildContext context) {
SizeConfig.init(context);
final auth = FirebaseAuth.instance;
return MultiProvider(
providers: [
//Providers go in here...
],
child: MaterialApp(
debugShowCheckedModeBanner: false,
title: 'livit',
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: mobileBackgroundColor,
),
home: StreamBuilder(
stream: auth.authStateChanges(),
builder: (context, snapshot) {
//over here we have logic to go to the login screen or the main page
},
),
),
);
}
}
应用程序检查用户是否已通过身份验证后,会将用户带到登录屏幕或主页。这就像一种魅力。不幸的是,用户尝试点击任何文本字段,他们无法输入,因为一旦他们聚焦,小部件就会重新加载。
所以我制作了一个干净的 flutter 项目,并编写了一个小部件来测试一切是否正常:
class TextInputTest extends StatefulWidget {
const TextInputTest({super.key, required this.title});
final String title;
@override
State<TextInputTest> createState() => _TextInputTestState();
}
class _TextInputTestState extends State<TextInputTest> {
final TextEditingController _controller = TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(
child: TextField(
controller: _controller,
),
),
);
}
}
它成功了,太棒了!我想指出的是,我所有使用文本字段的屏幕的格式都类似,因为它们是有状态的,并且控制器是在状态内声明的。
现在,如果我将完美工作的测试小部件放在流构建器通常所在的位置,那么该小部件就可以正常工作。但是,如果我替换登录屏幕或主页,测试小部件会出现同样的问题,整个小部件将在焦点上重新加载,并且用户将永远无法拉出屏幕。
你能帮我解决这个问题吗?我有点需要我的用户能够输入内容。
预先感谢您提供的任何帮助,如果您需要更多信息,请告诉我!
PS:我确实检查了这个帖子,但所有答案似乎都没有成果。
事实证明,通过将调用
auth.authStateChanges()
放入构建方法中(在本例中位于命名的 stream
参数中),每次调用构建时都会调用并重新创建流。每当键盘被拉起时,都会调用构建,因此将所有内容设置回原来的状态,包括我的文本字段处于初始的、未聚焦的状态。
这种情况下的解决方案是使小部件有状态(如果它还没有),声明一个变量以将流保持在状态中(而不是在任何方法中),然后为其指定值
auth.authStateChanges()
。就我而言,我必须使变量延迟并使用覆盖 initState() 来设置值,因为无法在初始化程序中访问 auth。
非常感谢Randal Schwartz发现了这个问题并发布了他的视频解释来解决这个问题。