flutter - 如何将 ModalProgressHUD 包含到另一个容器中?
问题描述
我正在使用https://pub.dev/packages/modal_progress_hud_nsn等待来自服务器的响应(它给了我们ModalProgressHUD
)。一切都是正确的,当我单击按钮时,会显示进度指示器,我们无法单击屏幕上的任何内容,这样可以防止使用相同的数据单击相同的按钮。
在登录屏幕中,如果有人没有激活帐户,底部的新容器会显示新按钮,用于重新发送确认邮件。问题是,当我们单击此新按钮并重新发送时,会显示指示器,但在此新容器“下方”,因此我可以无休止地单击此按钮并发出新请求。你能告诉我如何防止它,这样这个指标才能正常工作吗?
代码(我删掉了一些不必要的代码):
import 'dart:convert';
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:modal_progress_hud/modal_progress_hud.dart';
import 'package:renthings/constants/AppConstants.dart';
import 'package:renthings/constants/ErrorMessagesConstants.dart';
class LoginPage extends StatefulWidget {
final String email;
const LoginPage({Key? key, required this.email}) : super(key: key);
@override
_LoginPage createState() => _LoginPage();
}
class _LoginPage extends State<LoginPage> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final emailController = TextEditingController();
final passwordController = TextEditingController();
bool _isInAsyncCall = false;
var _passwordVisible = false;
@override
void dispose() {
emailController.dispose();
passwordController.dispose();
super.dispose();
}
@override
void initState() {
super.initState();
emailController.text = widget.email;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Zaloguj się"), centerTitle: true),
body: ModalProgressHUD(
progressIndicator: RefreshProgressIndicator(),
inAsyncCall: _isInAsyncCall,
child: SingleChildScrollView(
child: Container(
padding: EdgeInsets.all(20.0),
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
FlutterLogo(size: 130),
SizedBox(
height: 28.0,
),
Text(
'Zaloguj się przy użyciu e-maila oraz hasła',
style: TextStyle(
fontSize: 23,
),
textAlign: TextAlign.center,
),
SizedBox(
height: 26.0,
),
Form(
key: _formKey,
child: Column(
children: <Widget>[
TextFormField(
enabled: false,
controller: emailController,
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: 'Adres e-mail',
fillColor: Color(0xffffffff),
filled: true,
prefixIcon: Icon(Icons.mail),
),
),
SizedBox(
height: 10.0,
),
TextFormField(
controller: passwordController,
obscureText: !_passwordVisible,
decoration: InputDecoration(
errorMaxLines: 2,
border: OutlineInputBorder(),
hintText: 'Hasło',
fillColor: Color(0xffffffff),
filled: true,
prefixIcon: Icon(Icons.password),
suffixIcon: IconButton(
icon: Icon(
_passwordVisible
? Icons.visibility
: Icons.visibility_off,
color: Theme.of(context).primaryColorDark,
),
onPressed: () {
setState(() {
_passwordVisible = !_passwordVisible;
});
},
),
),
validator: (value) {
if (value == null || value.isEmpty) {
return ErrorMessages.NO_PASSWORD_MESSAGE;
}
},
),
SizedBox(
height: 25.0,
),
ConstrainedBox(
constraints:
BoxConstraints.tightFor(width: 240, height: 60),
child: ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
_tryToLogin();
}
},
child: Text('Zaloguj się',
style: TextStyle(
fontSize: 30,
color: Color(0xffffffff),
),
textAlign: TextAlign.center),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all<Color>(
Color(0xFF2F45C6),
),
shape: MaterialStateProperty.all<
RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(25.0),
),
),
),
),
),
SizedBox(
height: 25.0,
),
TextButton(
style: TextButton.styleFrom(
textStyle: const TextStyle(fontSize: 23),
),
onPressed: () {},
child: const Text('Zapomniałeś hasła?'),
),
],
),
)
],
),
),
),
),
backgroundColor: const Color(0xFEF9F9FC),
);
}
setLoading(bool state) => setState(() => _isInAsyncCall = state);
Future<void> _tryToLogin() async {
final body = {
'email': emailController.text.trim(), //
'password': passwordController.text, //
};
final jsonString = json.encode(body);
final uri =
Uri.http(AppConstants.BASE_URL, AppConstants.USER_ACTIVE_ENDPOINT);
final headers = {HttpHeaders.contentTypeHeader: 'application/json'};
setLoading(true);
final response = await http.post(uri, headers: headers, body: jsonString);
setLoading(false);
showNotActivatedAccountErrorPopup(context);
}
void showNotActivatedAccountErrorPopup(BuildContext context) {
showModalBottomSheet(
backgroundColor: Colors.transparent,
context: context,
builder: (BuildContext bc) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topRight: Radius.circular(40.0),
topLeft: Radius.circular(40.0),
),
color: const Color(0xFEF9F9FC),
boxShadow: [
BoxShadow(color: const Color(0xFF2F45C6), spreadRadius: 3),
],
),
height: MediaQuery.of(context).size.height * .27,
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Column(
children: <Widget>[
Text(
"Błąd!",
style: TextStyle(
fontSize: 30,
color: Color(0xffff0000),
),
textAlign: TextAlign.center,
),
SizedBox(
height: 10.0,
),
Text(
"Twój mail nie został jeszcze potwierdzony!",
style: TextStyle(
fontSize: 18,
color: Color(0xff000000),
),
textAlign: TextAlign.center,
),
SizedBox(
height: 15.0,
),
ConstrainedBox(
constraints: BoxConstraints.tightFor(width: 160, height: 40),
child: ElevatedButton(
child: Text('Rozumiem!',
style: TextStyle(
fontSize: 16,
color: Color(0xffffffff),
),
textAlign: TextAlign.center),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all<Color>(
Color(0xFF2F45C6),
),
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(25.0),
),
),
),
onPressed: () {
Navigator.of(context).pop();
},
),
),
SizedBox(height: 10),
TextButton(
style: TextButton.styleFrom(
textStyle: const TextStyle(fontSize: 17),
),
onPressed: () async {
http.Response response = await _resendConfirmationMail();
if (response.statusCode == 200) {
showDialog(
context: context,
builder: (context) {
Future.delayed(Duration(seconds: 3), () {
Navigator.of(context).pop(true);
});
return AlertDialog(
title: Text('Wysłano link potwierdzający!'),
);
});
}
},
child: const Text('Wyślij ponownie e-mail z potwierdzeniem'),
),
],
),
),
);
},
);
}
Future<http.Response> _resendConfirmationMail() async {
final queryParameters = {'mail': emailController.text};
final uri = Uri.http(AppConstants.BASE_URL,
AppConstants.RESEND_CONFIRMATION_ENDPOINT, queryParameters);
final headers = {HttpHeaders.contentTypeHeader: 'application/json'};
setLoading(true);
final response = await http.get(uri, headers: headers);
setLoading(false);
return response;
}
}
SetLoading 方法用于改变_isInAsyncCall
指示是否需要进度指示器的状态。
是单击容器上的_resendConfirmationMail
此new
按钮后调用的方法。new
感谢您的帮助。
解决方案
推荐阅读
- swift - '(key: String, value: Any)' 不能转换为 '[String : Any]'
- excel - 使用 Excel VBA 将 Word 内容复制到 Excel 电子表格中
- java - 如何 .count() list.stream() 的子对象?
- python - 如何用该列表中的前一个元素替换列表中超过某个阈值的元素?
- ruby-on-rails - 找不到 TasksController 的操作“new_status”
- php - PHP CURL 重定向
- python-3.x - 特殊字符仅作为字符串的一部分打印,但不独立打印(python3)
- azure - .NetCore 2.2 API 在使用用户分配的身份时无法从 AAD 获取令牌
- android - 有没有办法用片段着色器在顶点着色器的一个点的位置画一个圆?
- asp.net-mvc - 如何在运行时从 MVC 应用程序将参数传递给报表服务器上的 Power BI 报表