Flutter:如何从另一个外部 Class 调用依赖于 initState 的有状态小部件状态 Class 中的函数
Flutter: How to Call a Function that is in a Stateful Widgets State Class, that depends on the initState, from another external Class
我不确定以前是否有人问过这个问题,但我找不到答案。
我的登录页面有一个状态小部件,它使用 flutter_toast 程序包进行错误处理(密码不正确、电子邮件已在使用等)。使用 flutter_toast 时,为了制作自定义 toast,我必须使用登录页面的 initState 函数。
我还有另一个 class,在一个单独的文件中,我试图将我所有的 Firebase Auth 服务移到其中(这是我需要调用 showToast 函数的地方,该函数在 SigninState class).
我一直无法弄清楚如何在 AuthService class 中定义 showToast 函数,以便我可以在那里调用它。
这是我的登录状态小部件 class:
class Signin extends StatefulWidget {
const Signin({Key? key}) : super(key: key);
@override
_SigninState createState() => _SigninState();
}
class _SigninState extends State<Signin> {
FToast? fToast;
AuthService authService = AuthService();
@override
void initState() {
super.initState();
fToast = FToast();
fToast!.init(context);
}
...
// build function{
// in here, I call "authService.signInAction()", which needs to call "showToast()"
// }
...
}
showToast(String msg, context) {
bool smallPhone = false;
double width = MediaQuery.of(context).size.width;
if (width <= 370) smallPhone = true;
Widget toast = Container(
padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 12.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(25.0),
color: Colors.redAccent,
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(
width: 10.0,
),
Text(
msg,
style:
TextStyle(fontSize: smallPhone ? 13 : 15, color: Colors.white),
),
],
),
);
fToast!.showToast(
child: toast,
gravity: ToastGravity.CENTER,
toastDuration: const Duration(seconds: 2),
);
}
...
...
} // closing tag for _SigninState class
这是我的 AuthService class:
class AuthService {
FirebaseAuth auth = FirebaseAuth.instance;
Signin signin = const Signin();
UserModel _userFromFirebaseUser(User user) {
return UserModel(id: user.uid);
}
Stream<UserModel> get user {
return auth.authStateChanges().map((user) => _userFromFirebaseUser(user!));
}
Future signInAction(
String email, String password, BuildContext context) async {
try {
User user = (await auth.signInWithEmailAndPassword(
email: email, password: password)) as User;
_userFromFirebaseUser(user);
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => const MyHomePage(title: "Twitter")),
);
} on FirebaseAuthException catch (e) {
if (e.code == 'wrong-password') {
signin.showToast("The password provided is incorrect.", context); // <-- This does not work
} else if (e.code == 'user-not-found') {
signin.showToast("An account with that email does not exist.", context); // <-- This does not work
}
} catch (e) {
signin.showToast("An unexpected error has occurred.", context); // <-- This does not work
}
}
}
这是我遇到的错误:
The method 'showToast' isn't defined for the type 'Signin'.
Try correcting the name to the name of an existing method, or defining a method named 'showToast'
您可以使用回调,但我认为这不是一个优雅的解决方案。
signInAction(
String email, String password, {required void Function(String message) onError}) async {
try {
User user = (await auth.signInWithEmailAndPassword(
email: email, password: password)) as User;
_userFromFirebaseUser(user);
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => const MyHomePage(title: "Twitter")),
);
} on FirebaseAuthException catch (e) {
if (e.code == 'wrong-password') {
onError("The password provided is incorrect.");
} else if (e.code == 'user-not-found') {
onError("An account with that email does not exist.");
}
} catch (e) {
onError("An unexpected error has occurred.");
}
}
然后你可以调用
authService.signInAction(email, password,
onError:(message){
showToast(message, context);
}
)
这可能是可能的,但您可以轻松地改变它而不是您的方法。
设置静态字符串消息 = "";
and..
on FirebaseAuthException catch (e) {
if (e.code == 'wrong-password') {
message = "The password provided is incorrect.";
}
终于可以在Auth按钮中使用了..
showToast() {
bool smallPhone = false;
double width = MediaQuery.of(context).size.width;
if (width <= 370) smallPhone = true;
Widget toast = Container(
padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 12.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(25.0),
color: Colors.redAccent,
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(
width: 10.0,
),
Text(
AuthService.message,
style:
TextStyle(fontSize: smallPhone ? 13 : 15, color: Colors.white),
),
],
),
);
也许会有帮助
我不确定以前是否有人问过这个问题,但我找不到答案。
我的登录页面有一个状态小部件,它使用 flutter_toast 程序包进行错误处理(密码不正确、电子邮件已在使用等)。使用 flutter_toast 时,为了制作自定义 toast,我必须使用登录页面的 initState 函数。 我还有另一个 class,在一个单独的文件中,我试图将我所有的 Firebase Auth 服务移到其中(这是我需要调用 showToast 函数的地方,该函数在 SigninState class). 我一直无法弄清楚如何在 AuthService class 中定义 showToast 函数,以便我可以在那里调用它。
这是我的登录状态小部件 class:
class Signin extends StatefulWidget {
const Signin({Key? key}) : super(key: key);
@override
_SigninState createState() => _SigninState();
}
class _SigninState extends State<Signin> {
FToast? fToast;
AuthService authService = AuthService();
@override
void initState() {
super.initState();
fToast = FToast();
fToast!.init(context);
}
...
// build function{
// in here, I call "authService.signInAction()", which needs to call "showToast()"
// }
...
}
showToast(String msg, context) {
bool smallPhone = false;
double width = MediaQuery.of(context).size.width;
if (width <= 370) smallPhone = true;
Widget toast = Container(
padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 12.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(25.0),
color: Colors.redAccent,
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(
width: 10.0,
),
Text(
msg,
style:
TextStyle(fontSize: smallPhone ? 13 : 15, color: Colors.white),
),
],
),
);
fToast!.showToast(
child: toast,
gravity: ToastGravity.CENTER,
toastDuration: const Duration(seconds: 2),
);
}
...
...
} // closing tag for _SigninState class
这是我的 AuthService class:
class AuthService {
FirebaseAuth auth = FirebaseAuth.instance;
Signin signin = const Signin();
UserModel _userFromFirebaseUser(User user) {
return UserModel(id: user.uid);
}
Stream<UserModel> get user {
return auth.authStateChanges().map((user) => _userFromFirebaseUser(user!));
}
Future signInAction(
String email, String password, BuildContext context) async {
try {
User user = (await auth.signInWithEmailAndPassword(
email: email, password: password)) as User;
_userFromFirebaseUser(user);
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => const MyHomePage(title: "Twitter")),
);
} on FirebaseAuthException catch (e) {
if (e.code == 'wrong-password') {
signin.showToast("The password provided is incorrect.", context); // <-- This does not work
} else if (e.code == 'user-not-found') {
signin.showToast("An account with that email does not exist.", context); // <-- This does not work
}
} catch (e) {
signin.showToast("An unexpected error has occurred.", context); // <-- This does not work
}
}
}
这是我遇到的错误:
The method 'showToast' isn't defined for the type 'Signin'.
Try correcting the name to the name of an existing method, or defining a method named 'showToast'
您可以使用回调,但我认为这不是一个优雅的解决方案。
signInAction(
String email, String password, {required void Function(String message) onError}) async {
try {
User user = (await auth.signInWithEmailAndPassword(
email: email, password: password)) as User;
_userFromFirebaseUser(user);
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => const MyHomePage(title: "Twitter")),
);
} on FirebaseAuthException catch (e) {
if (e.code == 'wrong-password') {
onError("The password provided is incorrect.");
} else if (e.code == 'user-not-found') {
onError("An account with that email does not exist.");
}
} catch (e) {
onError("An unexpected error has occurred.");
}
}
然后你可以调用
authService.signInAction(email, password,
onError:(message){
showToast(message, context);
}
)
这可能是可能的,但您可以轻松地改变它而不是您的方法。 设置静态字符串消息 = "";
and..
on FirebaseAuthException catch (e) {
if (e.code == 'wrong-password') {
message = "The password provided is incorrect.";
}
终于可以在Auth按钮中使用了..
showToast() {
bool smallPhone = false;
double width = MediaQuery.of(context).size.width;
if (width <= 370) smallPhone = true;
Widget toast = Container(
padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 12.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(25.0),
color: Colors.redAccent,
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(
width: 10.0,
),
Text(
AuthService.message,
style:
TextStyle(fontSize: smallPhone ? 13 : 15, color: Colors.white),
),
],
),
);
也许会有帮助