flutter - Flutter 根据服务器响应显示 AlertDialog
问题描述
我目前正在尝试制作登录屏幕。到目前为止,我能够通过遵循他们的文档自己解决问题。
但是,我想实现我目前无法做的某件事,并且不确定如何进行。
基本算法是:
- 发送请求。
- 接收数据。[如果数据好->真,如果坏->假]
- 如果收到 true -> 移动到下一个屏幕。
- 如果收到错误 -> 显示带有消息的警报对话框(密码的用户名错误)
我还没有学过导航,但是我在这里看到了一个文档页面。我正计划遵循那个。如果还有什么我需要知道的,请告诉我。
当谈到警报对话框时 - 我知道如何显示它,但是当我尝试这样做时,它给了我这个错误:
返回类型“Future”不是闭包上下文所要求的 Widget
我理解该消息,但由于我对颤动很陌生,我不确定在我的情况下显示带有自定义消息的警报对话框的正确方法是什么。请帮帮我。
我将在下面发布代码。
login_ui.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:my_first_flutter_app/remotedatasource/httpClient.dart';
class LoginForm extends StatefulWidget {
@override
_LoginFormState createState() => _LoginFormState();
}
class _LoginFormState extends State<LoginForm> {
final _loginFormKey = GlobalKey<FormState>();
final _httpClient = new HttpClient();
final usernameController = TextEditingController();
final passwordController = TextEditingController();
Future<bool> userSignIn;
@override
void dispose() {
usernameController.dispose();
passwordController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Form(
key: _loginFormKey,
child: Center(
child: Container(
width: MediaQuery.of(context).size.width - 40,
height: 240,
margin: EdgeInsets.only(
left: 40, top: 40, right: 40, bottom: 40),
padding: EdgeInsets.only(
left: 15, top: 10, right: 15, bottom: 10),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10),
topRight: Radius.circular(10),
bottomLeft: Radius.circular(10),
bottomRight: Radius.circular(10)),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 5,
blurRadius: 7,
offset: Offset(0, 3), // changes position of shadow
),
],
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
TextFormField(
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.black,
),
borderRadius: BorderRadius.circular(10.0),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.black,
),
borderRadius: BorderRadius.circular(10.0),
),
hintText: 'Username'),
validator: (value) {
if (value.isEmpty) {
return 'Field is empty';
} else {
return null;
}
},
controller: usernameController,
),
TextFormField(
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.black,
),
borderRadius: BorderRadius.circular(10.0),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.black,
),
borderRadius: BorderRadius.circular(10.0),
),
hintText: 'Password'),
validator: (value) {
if (value.isEmpty) {
return 'Field is empty';
} else {
return null;
}
},
controller: passwordController,
obscureText: true,
enableSuggestions: false,
autocorrect: false,
),
SizedBox(
width: double.infinity,
height: 45,
child: ElevatedButton(
onPressed: () {
if (_loginFormKey.currentState.validate()) {
setState(() {
userSignIn = _httpClient.signIn(
usernameController.text,
passwordController.text);
});
}
}, //TODO->Send login data
child: Text(
'Submit',
textScaleFactor: 1.25,
))),
(userSignIn!=null)?FutureBuilder<bool>(
future: userSignIn,
builder: (context, snapshot) {
if(snapshot.hasData) {
return showDialog(
context: context,
builder: (context) {
return AlertDialog(
content: Text(
'Your data: \n username = ${usernameController.text} \n password = ${passwordController.text}'),
);
});
} else {
return Text('Failure');
}
}
) : null
]
))
));
}
}
main.dart
import 'package:flutter/material.dart';
import 'package:my_first_flutter_app/loginscreen/ui/login_ui.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus &&
currentFocus.focusedChild != null) {
currentFocus.focusedChild.unfocus();
}
},
child: MaterialApp(
title: 'Login',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: LoginForm(),
),
));
}
}
httpClient.dart
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:my_first_flutter_app/util/util.dart';
class HttpClient {
final String _loginURL = 'https://myurl/api/signin.api.php';
Future<bool> signIn(String username, String password) async {
final body = jsonEncode(<String, String>{
'username': username,
'password': password,
'qpalzm': getAccessKey()
});
final response = await http.post(_loginURL,
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: body);
if (response.statusCode == 200) {
print(response.body);
return true;
} else if (response.statusCode == 401) {
return false;
} else {
throw Exception('An unknown error occurred');
}
}
}
解决方案
你需要做2-3件事:
(1) 而不是 Future 将变量设置为仅 bool
bool userSignIn;
(2) 等待您的请求。所以而不是
onPressed: () {
if (_loginFormKey.currentState.validate()) {
setState(() {
userSignIn = _httpClient.signIn(
usernameController.text,
passwordController.text);
});
}
},
利用
onPressed: () async { //Use Async here
if (_loginFormKey.currentState.validate()) {
setState(() {
userSignIn = await _httpClient.signIn( //await here
usernameController.text,
passwordController.text);
});
}
},
(3) 你的show Dialog 没有返回Widget。它会绘制一个弹出窗口,您可以在其中拥有小部件。所以,
showDialog(
context: context,
builder: (context) {
return userSignIn ? LoginSuccessWidget() : LoginFailureWidget(); //Build what you want to show when login succeeds or fails, which could be AlertDialogs or Simple dialog or any other
});
推荐阅读
- angular - How to filter an array of object by comparing its id with the values of a different array
- python - 在 SciPy 中拟合分布时如何检查收敛性
- c# - 在 IOS 的 ionic 5 中安装 FCM 插件后,InAppBrowser 无法正常工作
- http - 将itm.txt数据转成json格式
- html - 把图片推到卡片外面后,只显示一半
- firebase - 如何从 Flutter Firestore 中的文档 ID 获取收藏列表?
- reactjs - React Hook Forms 验证显示错误,但现在我无法提交
- javascript - discord-buttons 无缘无故抛出错误
- java - 如果 a 和 b 具有相同的项目但不一定以相同的顺序返回 true,否则如果传递的数组中的任何一个为 null,则返回 false
- amazon-sqs - 使用 pubsub 架构解决竞争问题的最佳实践