Flutter中CircularProgressIndicator不生效,能否用FutureBuilder实现?
用FutureBuilder实现Firebase手机认证加载状态显示
当然可以用FutureBuilder实现这个需求,它能自动管理异步任务的状态,不用手动维护isLoading变量,还能避免手动调用setState可能出现的问题。以下是具体实现步骤和代码示例:
核心思路
通过将Firebase手机认证的异步任务(phoneSign)绑定到FutureBuilder,根据异步任务的状态(等待、完成、错误)自动切换UI:
- 任务等待时:显示
CircularProgressIndicator - 任务完成/初始状态:显示正常页面内容(手机号输入框、认证按钮)
- 任务出错时:显示错误提示并保留操作入口
具体代码实现
import 'package:flutter/material.dart'; import 'package:firebase_auth/firebase_auth.dart'; // 假设你的AuthMethods类定义如下 class AuthMethods { final FirebaseAuth _auth = FirebaseAuth.instance; Future<void> phoneSign(String phoneNumber, BuildContext context) async { await _auth.verifyPhoneNumber( phoneNumber: phoneNumber, verificationCompleted: (PhoneAuthCredential credential) async { await _auth.signInWithCredential(credential); }, verificationFailed: (FirebaseAuthException e) { throw e; // 抛出错误,让FutureBuilder捕获 }, codeSent: (String verificationId, int? resendToken) { // 跳转到验证码输入页面,传递verificationId Navigator.push( context, MaterialPageRoute( builder: (context) => VerificationPage(verificationId: verificationId), ), ); }, codeAutoRetrievalTimeout: (String verificationId) {}, ); } } class PhoneAuthPage extends StatefulWidget { const PhoneAuthPage({super.key}); @override State<PhoneAuthPage> createState() => _PhoneAuthPageState(); } class _PhoneAuthPageState extends State<PhoneAuthPage> { final TextEditingController _phoneController = TextEditingController(); Future<void>? _phoneSignFuture; // 保存异步任务的Future @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text("手机认证")), body: Padding( padding: const EdgeInsets.all(16.0), child: FutureBuilder( future: _phoneSignFuture, builder: (context, snapshot) { // 任务处于等待状态时,显示加载指示器 if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } // 任务出错时,显示错误信息+原表单 if (snapshot.hasError) { return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ TextField( controller: _phoneController, keyboardType: TextInputType.phone, decoration: const InputDecoration(hintText: "输入手机号"), ), const SizedBox(height: 16), ElevatedButton( onPressed: _triggerPhoneSign, child: const Text("发送验证码"), ), const SizedBox(height: 16), Text( "认证失败: ${snapshot.error.toString()}", style: const TextStyle(color: Colors.red), ), ], ); } // 初始状态或任务完成后,显示正常表单 return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ TextField( controller: _phoneController, keyboardType: TextInputType.phone, decoration: const InputDecoration(hintText: "输入手机号"), ), const SizedBox(height: 16), ElevatedButton( onPressed: _triggerPhoneSign, child: const Text("发送验证码"), ), ], ); }, ), ), ); } void _triggerPhoneSign() { final phoneNumber = _phoneController.text.trim(); if (phoneNumber.isNotEmpty) { setState(() { // 将异步任务赋值给Future变量,触发FutureBuilder更新状态 _phoneSignFuture = AuthMethods().phoneSign(phoneNumber, context); }); } } @override void dispose() { _phoneController.dispose(); super.dispose(); } } // 示例验证码输入页面 class VerificationPage extends StatelessWidget { final String verificationId; const VerificationPage({super.key, required this.verificationId}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text("输入验证码")), body: const Center(child: TextField(decoration: InputDecoration(hintText: "输入6位验证码"))), ); } }
关键说明
_phoneSignFuture变量:用来保存phoneSign方法的异步任务,每次点击按钮时通过setState更新它,触发FutureBuilder重新构建UI。- ConnectionState判断:通过
snapshot.connectionState == ConnectionState.waiting直接判断任务是否在执行,无需手动维护isLoading。 - 错误处理:在
phoneSign方法中抛出认证错误,FutureBuilder会通过snapshot.hasError捕获并显示错误信息。
内容的提问来源于stack exchange,提问作者Harshana
相关产品推荐
相关产品推荐

