我目前正在按照此視頻處理Flutter 應用程式的登錄螢屏。因此,我的代碼幾乎與GitHub 上此視頻的代碼完全相同。
我添加了一種在當前狀態下存盤用戶電子郵件和密碼的方法,并在登錄按鈕按下后立即將 CircularProgressIndicator 添加到登錄按鈕。
后者由以下代碼完成(我洗掉了所有與樣式相關的代碼以使其更具可讀性):
Widget _buildLoginBtn() {
return Container(
padding: EdgeInsets.symmetric(vertical: 25.0),
child: ElevatedButton(
child: _isLoggingIn ? Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("Login"),
Padding(
padding: EdgeInsets.symmetric(horizontal: 20),
child: SizedBox(
child: CircularProgressIndicator(),
),
)
],
) : Text("Login"),
onPressed: () => _handleLogin(),
),
);
}
本來我只是想測驗一下,改變狀態是否真的會導致CircularProgressIndicator被設定_isLoggingIn為顯示true。
在我看到這作業正常后,我想成功,以便 CircularProgressIndicator 在一段時間后再次消失(例如,如果登錄嘗試被拒絕)。因此,正如我現在還沒有建立一個API,我只是想在應用程式通過設定打開進度條關閉之前等待幾秒鐘_isLoggingIn到false一次。
然而,事實證明,因此沒有任何明顯的反應(只有控制臺輸出指示等待),或者 - 如果我_isLoggingIn之前設定為true- 進度條只是停止旋轉 3 秒然后消失。
這是以下代碼的結果:
void _handleLogin() {
setState(() {
_isLoggingIn = true;
});
print("Start Logging In");
sleep(Duration(seconds: 3));
print("Stop Logging In");
setState(() {
_isLoggingIn = false;
});
}
From a logical point of view this seems very logical as I basically just block the main thread, so the UI is only updated after I set _isLoggingIn to true and to false again.
I instantly thought about some functionality for async processing. I read some things on async-await, the Future function type and the FutureBuilder but as I'm pretty new to Flutter I didn't really grasp which functions to make async and also which function type I need to convert to Future<void> or how to properly trigger the async processing. Also I didn't really deal with Futures and async-await statements prior to this.
So I hope someone could give me some insight into this topic and how to solve this problem properly?
uj5u.com熱心網友回復:
不需要包使用 mvvm 格式,而且對于指標,會有一個小部件名稱 CupertinoActivityIndi??cator 使用它
uj5u.com熱心網友回復:
我發現這篇文章討論了資料加載期間用戶與應用程式的互動并提供了解決方案。最后,我切換到一個對話框,該對話框顯示CircularProgressIndicator加載并同時阻止任何 UI 互動。
因此,用戶將無法同時發送多個登錄請求,同時也向用戶指示正在加載資料。
在這篇文章的幫助下,我的應用程式終于按照我的意愿運行了。
對于遇到類似問題的任何人,我強烈建議通讀該文章并考慮使用那里提供的代碼。但是,需要實施額外的空安全檢查。
uj5u.com熱心網友回復:
我總是使用 Flutter 包EasyLoading,因為它簡化了這個程序!不需要使用 bool 和 setstate 來添加回圈進度指示器。
import 'package:flutter_easyloading/flutter_easyloading.dart';
class MyApp extends StatelessWidget {
// This widget is the root of your application. (main.dart)
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter EasyLoading',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter EasyLoading'),
//initialize Easyloading
builder: EasyLoading.init(),
);
}
}
Widget _buildLoginBtn() {
return Container(
padding: EdgeInsets.symmetric(vertical: 25.0),
child: ElevatedButton(
child: Text("Login"),
onPressed: () => _handleLogin(),
),
);
}
void _handleLogin() {
EasyLoading.show(dismissOnTap: false, status: "Loading...");
print("Start Logging In");
sleep(Duration(seconds: 3));
print("Stop Logging In");
EasyLoading.dismiss();
}
uj5u.com熱心網友回復:
ProgressIndicator - 3 種方式
以下是我們可以隱藏/禁用登錄按鈕和顯示/隱藏進度指示器的 3 種不同方式:
showDialog(即一個ModalBarrier)StatefulWidgetValueListenableBuilder
showDialog 在頂部推動和彈出一個半透明的障礙(路線/頁面)。
StatefulWidget并ValueListenableBuilder重建自己以洗掉/替換小部件。
showDialog
showDialog內部使用 aModalBarrier來阻止與下方小部件的互動。
這不需要保持任何狀態。
我們只是在登錄進行時阻止互動/顯示微調器,然后pop()在我們完成后(或達到超時持續時間)阻止頁面/路由。
class ProgressShowDialog extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: OutlinedButton(
child: Text('Login'),
onPressed: () async => login(context)
),
);
}
Future<void> login(BuildContext context) async {
// show (push onto route stack) a modal barrier, blocking UI
showDialog(context: context,
builder: (context) => Center(child: SizedBox(height:30, width: 30,
child: CircularProgressIndicator())), barrierDismissible: false);
// a fake login call using Future.delayed
bool loginOK = await Future.delayed(Duration(seconds: 3), () => true)
.timeout(Duration(seconds: 5), onTimeout: () => false);
// dispose the dialog modal barrier (pop it from route stack)
Navigator.of(context).pop(loginOK);
// do something with login result
print('Login OK? $loginOK');
}
}
注意:我們可以為任何Futureusing設定超時/處理程式.timeout()。
StatefulWidget
在這里,我們使用狀態變數isLoggingIn并setState()在更改其值時呼叫,以重建StatefulWidget, 以顯示/隱藏表單/進度指示器。
class ProgressStateful extends StatefulWidget {
@override
_ProgressStatefulState createState() => _ProgressStatefulState();
}
class _ProgressStatefulState extends State<ProgressStateful> {
bool isLoggingIn = false;
@override
Widget build(BuildContext context) {
return Center(
child: _loginFormOrProgress,
);
}
Widget get _loginFormOrProgress {
// if log in ongoing, show spinner
if (isLoggingIn) {
return SizedBox(height: 80, width: 80, child: CircularProgressIndicator(),);
}
else {
// otherwise show login form
return OutlinedButton(
child: Text('Login'),
onPressed: () async => login(context)
);
}
}
Future<void> login(BuildContext context) async {
loginOngoing(true); // rebuild, show spinner/hide login btn
bool loginOK = await Future.delayed(Duration(seconds: 3), () => true)
.timeout(Duration(seconds: 5),
onTimeout: () => false);
// Do something fun with login results
print('Login OK? $loginOK');
loginOngoing(false); // rebuild & hide spinner/show form
}
void loginOngoing(bool loginOngoing) {
setState(() {
isLoggingIn = loginOngoing;
});
}
}
ValueListenableBuilder
這類似于StatefulWidget除了使用一些 Flutter 基礎類(ValueNotifier& ValueListenableBuilder)來setState()為我們處理重建(呼叫)。
class ProgressValueListenable extends StatefulWidget {
@override
_ProgressValueListenableState createState() => _ProgressValueListenableState();
}
class _ProgressValueListenableState extends State<ProgressValueListenable> {
ValueNotifier<bool> loginOngoing = ValueNotifier(false);
@override
Widget build(BuildContext context) {
return Center(
child: ValueListenableBuilder( // rebuilds whenever loginOngoing changes (receives an event)
valueListenable: loginOngoing,
builder: (context, value, child) {
// if login ongoing, show spinner
if (value) {
return SizedBox(height: 80, width: 80, child: CircularProgressIndicator(),);
}
else {
// otherwise show login form
return OutlinedButton(
child: Text('Login'),
onPressed: () async => login()
);
}
}),
);
}
void login() async {
loginOngoing.value = true; // show spinner
// login call happens here ↓
bool loginOK = await Future.delayed(Duration(seconds: 3), () => true)
.timeout(Duration(seconds: 2),
onTimeout: () => false);
// Do something fun with login results
print('Login OK? $loginOK');
loginOngoing.value = false; // hide spinner
}
@override
void dispose() {
loginOngoing.dispose();
super.dispose();
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/360672.html
標籤:flutter asynchronous async-await future flutter-futurebuilder
上一篇:當異步行程結束時Kotlin回傳
