FlutterLogin
是一个现成的登录/注册组件,具有多种动画效果,展示了Flutter的强大功能。
请按照这里的安装说明进行操作。
属性 | 类型 | 描述 |
---|---|---|
onSignup | AuthCallback | <sub>当用户在注册模式下点击提交按钮时调用。它接收一个SignupData 对象,包含姓名、密码,如果additionalSignUpFields 不为空,还包含用户填写的额外字段,以Map<String,String> 形式提供。</sub> |
onConfirmSignup | ConfirmSignupCallback | <sub>当用户在确认注册时点击提交按钮时调用。如果未指定,用户将不需要确认注册。</sub> |
confirmSignupRequired | ConfirmSignupRequiredCallback | <sub>用于在运行时决定是否需要确认的附加选项。如果未指定,当onConfirmSignup被指定时,用户将需要确认注册。</sub> |
confirmSignupKeyboardType | TextInputType | <sub>确认注册字段的键盘类型</sub> |
onResendCode | AuthCallback | <sub>当用户在确认注册时点击重新发送代码按钮时调用。仅在提供onConfirmSignup时需要。</sub> |
onLogin | AuthCallback | <sub>当用户在登录模式下点击提交按钮时调用</sub> |
onRecoverPassword | RecoverCallback | <sub>当用户在找回密码模式下点击提交按钮时调用</sub> |
onConfirmRecover | ConfirmRecoverCallback | <sub>当用户在找回密码模式下提交确认码并设置新密码时调用。如果未指定,将不使用确认码来找回密码。</sub> |
title | String | <sub>登录[Card]上方的大文本,通常是应用或公司名称。如果不需要标题,将字符串留空或设为null。</sub> |
logo | ImageProvider或String | <sub>要显示的logo图像的图像提供者或资源路径字符串</sub> |
messages | LoginMessages | <sub>描述所有标签、文本提示、按钮文本和其他认证描述</sub> |
theme | LoginTheme | <sub>FlutterLogin的主题。如果未指定,将使用默认主题,如演示gif所示,并使用最近的Theme 小部件中的配色方案</sub> |
userType | LoginUserType | <sub>FlutterLogin的用户类型。如果未指定,将使用默认的电子邮件用户类 型</sub> |
userValidator | <sub>FormFieldValidator<String> </sub> | <sub>用户字段验证逻辑,在此添加自定义验证。默认为电子邮件验证逻辑。预期返回验证失败时显示的错误消息[String],或验证成功时返回[null]</sub> |
validateUserImmediately | <sub>bool </sub> | <sub>是在失去焦点后立即验证电子邮件[true]还是在表单提交后验证[false]。默认:[false]</sub> |
passwordValidator | <sub>FormFieldValidator<String> </sub> | <sub>与userValidator 相同,但用于密码</sub> |
<sub>onSubmitAnimationCompleted</sub> | Function | <sub>在提交动画完成后调用。在此处放置路由转换逻辑</sub> |
logoTag | String | <sub>logo图像的Hero 标签。如果未指定,在更改路由时它将简单地淡出</sub> |
titleTag | String | <sub>标题文本的Hero 标签。如果想要在hero动画前后使用不同的字体大小,需要指定LoginTheme.beforeHeroFontSize 和LoginTheme.afterHeroFontSize </sub> |
showDebugButtons | bool | <sub>显示调试按钮以快速前进/后退登录动画。在发布模式下,无论传入的值如何,此项都将被覆盖为false </sub> |
hideForgotPasswordButton | bool | <sub>如果设置为true,则隐藏"忘记密码"按钮</sub> |
hideProvidersTitle | bool | <sub>如果设置为true,则隐藏登录提供商上方的标题。如果提供商列表为空,这将无效,因为标题无论如何都会被隐藏。默认为false </sub> |
disableCustomPageTransformer | bool | <sub>禁用自定义转换,以解决RenderBox未布局错误。有关更多信息,请参见#97。</sub> |
additionalSignUpFields | Map<String, UserFormField> | <sub>用于指定额外的表单字段;该表单在注册后立即显示。最多可以提供6个额外字段。</sub> |
onSwitchToAdditionalFields | AdditionalFieldsCallback | <sub>当用户切换到额外字段时调用。</sub> |
navigateBackAfterRecovery | bool | <sub>成功找回密码后导航回登录页面。</sub> |
savedEmail | String | <sub>用户字段的预填值(例如,通过其他方式从上一个会话保存,如通过SharedPreferences)</sub> |
savedPassword | String | <sub>密码字段的预填值(例如,通过其他方式从上一个会话保存,如通过SharedPreferences)。也会在Auth类中设置确认密码</sub> |
termsOfService | TermOfService | <sub>注册期间要列出的服务条款列表。在onSignup回调中,LoginData包含TermOfServiceResult 列表</sub> |
children | [Widget ] | <sub>可以添加到登录屏幕堆栈的小部件列表。可用于显示自定义横幅或logo。</sub> |
scrollable | bool | <sub>当设置为true时,登录卡片在需要时会变为可滚动而不是调整大小。</sub> |
headerWidget | Widget | <sub>可以放置在登录卡片顶部的小部件。</sub> |
注意: 建议在两个地方使用相同的子部件作为 Hero 部件的子部件。对于标题的hero动画,在下一个界面中使用 LoginThemeHelper.loginTextStyle 来获取登录界面中精确文本部件的样式。可以通过添加以下行来访问 LoginThemeHelper : |
import 'package:flutter_login/theme.dart';
属性 | 类型 | 描述 |
---|---|---|
userHint | String | 用户字段[TextField]的提示文本(注:用户字段可以是名称、邮箱或电话。更多信息请查看:LoginUserType ) |
passwordHint | String | 密码[TextField]的提示文本 |
confirmPasswordHint | String | 确认密码[TextField]的提示文本 |
forgotPasswordButton | String | 忘记密码按钮的标签 |
loginButton | String | 登录按钮的标签 |
signupButton | String | 注册按钮的标签 |
recoverPasswordButton | String | 找回密码按钮的标签 |
recoverPasswordIntro | String | 密码找回表单的介绍文本 |
recoverPasswordDescription | String | 密码找回表单的描述,当未提供onConfirmRecover回调时显示 |
recoverCodePasswordDescription | String | 密码找回表单的描述,当提供onConfirmRecover回调时显示 |
goBackButton | String | 返回按钮的标签。用于从密码找回表单返回到登录/注册表单 |
confirmPasswordError | String | 当确认密码与原始密码不匹配时显示的错误消息 |
recoverPasswordSuccess | String | 提交密码找回后显示的成功消息 |
confirmSignupIntro | String | 确认注册卡片的介绍文本 |
confirmationCodeHint | String | 确认码[TextField]的提示文本 |
confirmationCodeValidationError | String | 当确认码为空时显示的错误消息 |
resendCodeButton | String | 重新发送验证码按钮的标签 |
resendCodeSuccess | String | 重新发送确认码后显示的成功消息 |
confirmSignupButton | String | 确认注册按钮的标签 |
confirmSignupSuccess | String | 确认注册后显示的成功消息 |
confirmRecoverIntro | String | 确认找回密码卡片的介绍文本 |
recoveryCodeHint | String | 恢复码[TextField]的提示文本 |
recoveryCodeValidationError | String | 当恢复码为空时显示的错误消息 |
setPasswordButton | String | 密码找回时设置密码按钮的标签 |
confirmRecoverSuccess | String | 确认找回密码后显示的成功消息 |
flushbarTitleError | String | 错误情况下Flushbar的标题 |
flushbarTitleSuccess | String | 成功情况下Flushbar的标题 |
providersTitle | String | 显示在登录提供商上方的字符串,默认为"或通过以下方式登录" |
属性 | 类型 | 描述 |
---|---|---|
primaryColor | Color | 部件主要部分的背景色,如登录界面和按钮 |
accentColor | Color | 次要颜色,用于标题文本颜色、加载图标等。应与[primaryColor]形成对比 |
errorColor | Color | 用于[TextField]输入验证错误的颜色 |
cardTheme | CardTheme | 用于渲染认证[Card]的颜色和样式 |
inputTheme | InputDecorationTheme | 定义所有[TextField]的外观 |
buttonTheme | LoginButtonTheme | 用于自定义提交按钮的形状、高度和颜色的主题 |
titleStyle | TextStyle | 大标题的文本样式 |
bodyStyle | TextStyle | 小文本的文本样式,如找回密码描述 |
textFieldStyle | TextStyle | [TextField]输入文本的文本样式 |
buttonStyle | TextStyle | 按钮文本的文本样式 |
beforeHeroFontSize | double | 定义登录界面中标题的字体大小(hero转换前) |
afterHeroFontSize | double | 定义登录界面后的界面中标题的字体大小(hero转换后) |
pageColorLight | Color | 登录界面的可选浅色背景色;如果提供,用于浅色渐变而不是primaryColor |
pageColorDark | Color | 登录界面的可选深色背景色;如果提供,用于深色渐变而不是primaryColor |
footerBottomPadding | double | 页脚底部内边距;如果未提供,默认为0 |
switchAuthTextColor | Color | 切换认证文本的可选颜色,如果未指定则使用[primaryColor] |
logoWidth | double | logo的宽度,其中1为登录卡片的全宽。如果未提供,默认为0.75 |
primaryColorAsInputLabel | bool | 如果你想使用主色作为输入标签,设置为true。默认为false |
枚举 | 描述 |
---|---|
用户字段将设置为电子邮件 | |
NAME | 用户字段将设置为用户名 |
FIRSTNAME | 用户字段将设置为名字 |
LASTNAME | 用户字段将设置为姓氏 |
PHONE | 用户字段将设置为电话号码 |
INTLPHONE | 用户字段将设置为带国家代码选择的电话号码 |
TEXT | 用户字段将设置为文本 |
[LoginUserType]将改变用户字段[TextField]的行为。自动填充和键盘类型将根据你传递的用户类型自动调整。
属性 | 类型 | 描述 |
---|---|---|
keyName | String | 字段的标识符,它将作为返回映射中的键。请确保这是唯一的,否则将抛出错误 |
displayName | String | 表单上显示的字段名称。如果未给出,默认为keyName |
defaultValue | String | 字段的默认值,如果给出,字段将预填充此值 |
fieldValidator | FormFieldValidator<String> | 验证字段的函数。成功时应返回null,或返回一个包含错误说明的字符串 |
icon | Icon? | 字段左侧显示的图标。未提供时默认为用户图标 |
userType | LoginUserType | 表单的LoginUserType。将根据此类型显示相应的键盘和建议。默认为LoginUserType.user |
tooltip | InlineSpan | 该字段的附加描述 |
属性 | 类型 | 描述 |
---|---|---|
button | Widget | 用于 [LoginProvider] 的按钮 - 参见示例使用 [SignInButton] 包 |
icon | IconData | [LoginProvider] 按钮使用的图标 |
label | String | 提供商下方显示的标签 |
callback | ProviderAuthCallback | 当按下提供商按钮时调用的函数。成功时必须返回 null,失败时返回描述错误的 String 。 |
providerNeedsSignUpCallback | ProviderNeedsSignUpCallback? | 可选。要求将 additionalSignUpFields 参数传递给 FlutterLogin 。如果给出,此回调必须返回 Future<bool> 。如果评估为 true ,则在评估 callback 后立即显示包含额外注册字段的卡片。如果未给出,默认行为是不显示注册卡片。 |
注意: [button] 和 [icon] 都可以添加到 [LoginProvider],但 [button] 优先于 [icon]
属性 | 类型 | 描述 |
---|---|---|
id | String | 仅在注册回调中用于标识单个可选的服务条款。 |
mandatory | bool | 如果设置为 true,且在提交表单验证时未勾选该条款,将显示验证错误消息。 |
text | String | 显示的服务条款名称。 |
linkUrl | String | 指向附加服务条款信息的网页链接。 |
validationErrorMessage | String | 要显示的验证错误消息。 |
initialValue | bool | 指定复选框是否初始化为已选中状态。 |
属性 | 类型 | 描述 |
---|---|---|
term | TermOfService | 包含一个服务条款对象。 |
accepted | bool | 表示在注册过程中是否选择了该服务条款 |
你可以在 示例项目 中查看完整示例,该示例产生了上面的 gif 效果
<img src="https://yellow-cdn.veclightyear.com/835a84d5/a3eaf7cb-82d4-4af7-932e-877d6fa8a2b2.png" width="300">import 'package:flutter/material.dart'; import 'package:flutter_login/flutter_login.dart'; import 'dashboard_screen.dart'; const users = { 'dribbble@gmail.com': '12345', 'hunter@gmail.com': 'hunter', }; class LoginScreen extends StatelessWidget { const LoginScreen({super.key}); Duration get loginTime => const Duration(milliseconds: 2250); Future<String?> _authUser(LoginData data) { debugPrint('Name: ${data.name}, Password: ${data.password}'); return Future.delayed(loginTime).then((_) { if (!users.containsKey(data.name)) { return 'User not exists'; } if (users[data.name] != data.password) { return 'Password does not match'; } return null; }); } Future<String?> _signupUser(SignupData data) { debugPrint('Signup Name: ${data.name}, Password: ${data.password}'); return Future.delayed(loginTime).then((_) { return null; }); } Future<String> _recoverPassword(String name) { debugPrint('Name: $name'); return Future.delayed(loginTime).then((_) { if (!users.containsKey(name)) { return 'User not exists'; } return null; }); } Widget build(BuildContext context) { return FlutterLogin( title: 'ECORP', logo: const AssetImage('assets/images/ecorp-lightblue.png'), onLogin: _authUser, onSignup: _signupUser, onSubmitAnimationCompleted: () { Navigator.of(context).pushReplacement(MaterialPageRoute( builder: (context) => const DashboardScreen(), )); }, onRecoverPassword: _recoverPassword, ); } }
<img src="https://yellow-cdn.veclightyear.com/835a84d5/23cf357e-65c4-4122-af0d-2ffb7bd1dbf7.png" width="300">import 'package:flutter/material.dart'; import 'package:flutter_login/flutter_login.dart'; import 'dashboard_screen.dart'; const users = { 'dribbble@gmail.com': '12345', 'hunter@gmail.com': 'hunter', }; class LoginScreen extends StatelessWidget { const LoginScreen({super.key}); Duration get loginTime => const Duration(milliseconds: 2250); Future<String?> _authUser(LoginData data) { debugPrint('Name: ${data.name}, Password: ${data.password}'); return Future.delayed(loginTime).then((_) { if (!users.containsKey(data.name)) { return 'User not exists'; } if (users[data.name] != data.password) { return 'Password does not match'; } return null; }); } Future<String?> _signupUser(SignupData data) { debugPrint('Signup Name: ${data.name}, Password: ${data.password}'); return Future.delayed(loginTime).then((_) { return null; }); } Future<String> _recoverPassword(String name) { debugPrint('Name: $name'); return Future.delayed(loginTime).then((_) { if (!users.containsKey(name)) { return 'User not exists'; } return null; }); } Widget build(BuildContext context) { return FlutterLogin( title: 'ECORP', logo: const AssetImage('assets/images/ecorp-lightblue.png'), onLogin: _authUser, onSignup: _signupUser, loginProviders: <LoginProvider>[ LoginProvider( icon: FontAwesomeIcons.google, label: 'Google', callback: () async { debugPrint('start google sign in'); await Future.delayed(loginTime); debugPrint('stop google sign in'); return null; }, ), LoginProvider( icon: FontAwesomeIcons.facebookF, label: 'Facebook', callback: () async { debugPrint('start facebook sign in'); await Future.delayed(loginTime); debugPrint('stop facebook sign in'); return null; }, ), LoginProvider( icon: FontAwesomeIcons.linkedinIn, callback: () async { debugPrint('start linkdin sign in'); await Future.delayed(loginTime); debugPrint('stop linkdin sign in'); return null; }, ), LoginProvider( icon: FontAwesomeIcons.githubAlt, callback: () async { debugPrint('start github sign in'); await Future.delayed(loginTime); debugPrint('stop github sign in'); return null; }, ), ], onSubmitAnimationCompleted: () { Navigator.of(context).pushReplacement(MaterialPageRoute( builder: (context) => const DashboardScreen(), )); }, onRecoverPassword: _recoverPassword, ); } }
ThemeData
进行主题定制登录主题可以通过使用 ThemeData
间接定制,如下所示
<img src="https://yellow-cdn.veclightyear.com/835a84d5/e2157fed-9bff-4818-8aba-6ffbb5fc4f50.png" width="300">// main.dart import 'package:flutter/material.dart'; import 'login_screen.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { Widget build(BuildContext context) { return MaterialApp( title: '登录演示', theme: ThemeData( primarySwatch: Colors.deepPurple, accentColor: Colors.orange, cursorColor: Colors.orange, textTheme: const TextTheme( headline3: TextStyle( fontFamily: 'OpenSans', fontSize: 45.0, color: Colors.orange, ), button: TextStyle( fontFamily: 'OpenSans', ), subtitle1: TextStyle(fontFamily: 'NotoSans'), bodyText2: TextStyle(fontFamily: 'NotoSans'), ), ), home: LoginScreen(), ); } } // login_screen.dart import 'package:flutter/material.dart'; import 'package:flutter_login/flutter_login.dart'; import 'dashboard_screen.dart'; class LoginScreen extends StatelessWidget { Widget build(BuildContext context) { return FlutterLogin( title: 'ECORP', logo: const AssetImage('assets/images/ecorp.png'), onLogin: (_) => Future(null), onSignup: (_) => Future(null), onSubmitAnimationCompleted: () { Navigator.of(context).pushReplacement(MaterialPageRoute( builder: (context) => const DashboardScreen(), )); }, onRecoverPassword: (_) => Future(null), ); } }
import 'package:flutter/material.dart'; import 'package:flutter_login/flutter_login.dart'; import 'dashboard_screen.dart'; class LoginScreen extends StatelessWidget { const LoginScreen({super.key}); Widget build(BuildContext context) { return FlutterLogin( title: 'ECORP', logo: const AssetImage('assets/images/ecorp.png'), onLogin: (_) => Future(null), onSignup: (_) => Future(null), onSubmitAnimationCompleted: () { Navigator.of(context).pushReplacement(MaterialPageRoute( builder: (context) => const DashboardScreen(), )); }, onRecoverPassword: (_) => Future(null), messages: LoginMessages( userHint: '用户', passwordHint: '密码', confirmPasswordHint: '确认', loginButton: '登录', signupButton: '注册', forgotPasswordButton: '忘记密码?', recoverPasswordButton: '帮助', goBackButton: '返回', confirmPasswordError: '不匹配!', recoverPasswordDescription: 'Lorem Ipsum是印刷和排版行业的虚拟文本', recoverPasswordSuccess: '密码成功找回', ), ); } }
登录/注册 | 密码找回 |
---|---|
![]() | ![]() |
<img src="https://yellow-cdn.veclightyear.com/835a84d5/0afacd9a-be2a-4f6a-9f57-046902a16ef5.png" width="300">import 'package:flutter/material.dart'; import 'package:flutter_login/flutter_login.dart'; import 'dashboard_screen.dart'; class LoginScreen extends StatelessWidget { const LoginScreen({super.key}); Widget build(BuildContext context) { const inputBorder = BorderRadius.vertical( bottom: Radius.circular(10.0), top: Radius.circular(20.0), ); return FlutterLogin( title: 'ECORP', logo: const AssetImage('assets/images/ecorp-lightgreen.png'), onLogin: (_) => Future(null), onSignup: (_) => Future(null), onSubmitAnimationCompleted: () { Navigator.of(context).pushReplacement(MaterialPageRoute( builder: (context) => const DashboardScreen(), )); }, onRecoverPassword: (_) => Future(null), theme: LoginTheme( primaryColor: Colors.teal, accentColor: Colors.yellow, errorColor: Colors.deepOrange, titleStyle: const TextStyle( color: Colors.greenAccent, fontFamily: 'Quicksand', letterSpacing: 4, ), bodyStyle: const TextStyle( fontStyle: FontStyle.italic, decoration: TextDecoration.underline, ), textFieldStyle: const TextStyle( color: Colors.orange, shadows: [Shadow(color: Colors.yellow, blurRadius: 2)], ), buttonStyle: const TextStyle( fontWeight: FontWeight.w800, color: Colors.yellow, ), cardTheme: CardTheme( color: Colors.yellow.shade100, elevation: 5, margin: const EdgeInsets.only(top: 15), shape: ContinuousRectangleBorder( borderRadius: BorderRadius.circular(100.0)), ), inputTheme: InputDecorationTheme( filled: true, fillColor: Colors.purple.withOpacity(.1), contentPadding: EdgeInsets.zero, errorStyle: const TextStyle( backgroundColor: Colors.orange, color: Colors.white, ), labelStyle: const TextStyle(fontSize: 12), enabledBorder: UnderlineInputBorder( borderSide: BorderSide(color: Colors.blue.shade700, width: 4), borderRadius: inputBorder, ), focusedBorder: UnderlineInputBorder( borderSide: BorderSide(color: Colors.blue.shade400, width: 5), borderRadius: inputBorder, ), errorBorder: UnderlineInputBorder( borderSide: BorderSide(color: Colors.red.shade700, width: 7), borderRadius: inputBorder, ), focusedErrorBorder: UnderlineInputBorder( borderSide: BorderSide(color: Colors.red.shade400, width: 8), borderRadius: inputBorder, ), disabledBorder: const UnderlineInputBorder( borderSide: BorderSide(color: Colors.grey, width: 5), borderRadius: inputBorder, ), ), buttonTheme: LoginButtonTheme( splashColor: Colors.purple, backgroundColor: Colors.pinkAccent, highlightColor: Colors.lightGreen, elevation: 9.0, highlightElevation: 6.0, shape: BeveledRectangleBorder( borderRadius: BorderRadius.circular(10), ), // shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)), // shape: CircleBorder(side: BorderSide(color: Colors.green)), // shape: ContinuousRectangleBorder(borderRadius: BorderRadius.circular(55.0)), ), ), ); } }
一站式AI创作平台
提供 AI 驱动的图片、视频生成及数字人等功能,助力创意创作
AI办公助手,复杂任务高效处理
AI办公助手,复杂任务高效处理。办公效率低?扣子空间AI助手支持播客生成、PPT制作、网页开发及报告写作,覆盖科研、商业、舆情等领域的专家Agent 7x24小时响应,生活工作无缝切换,提升50%效率!
AI数字人视频创作平台
Keevx 一款开箱即用的AI数字人视频创作平台,广泛适用于电商广告、企业培训与社媒宣传,让全球企业与个人创作者无需拍摄剪辑,就能快速生成多语言、高质量的专业视频。
AI辅助编程,代码自动修复
Trae是一种自适应的集成开发环境(IDE),通过自动化和多元协作改变开发流程。利用Trae,团队能够更快速、精确地编写和部署代码,从而提高编程效率和项目交付速度。Trae具备上下文感知和代码自动完成功能,是提升开发效率的理想工具。
AI小说写作助手,一站式润色、改写、扩写
蛙蛙写作—国内先进的AI写作平台,涵盖小说、学术、社交媒体等多场景。提供续写、改写、润色等功能,助力创作者高效优化写作流程。界面简洁,功能全面,适合各类写作者提升内容品质和工作效率。
全能AI智能助手,随时解答生活与工作的多样问题
问小白,由元石科技研发的AI智能助手,快速准确地解答各种生活和工作问题,包括但不限于搜索、规划和社交互动,帮助用户在日常生活中提高效率,轻松管理个人事务。
实时语音翻译/同声传译工具
Transly是一个多场景的AI大语言模型驱动的同声传译、专业翻译助手,它拥有超精准的音频识别翻译能力,几乎零延迟的使用体验和支持多国语言可以让你带它走遍全球,无论你是留学生、商务人士、韩剧美剧爱好者,还是出国游玩、多国会议、跨国追星等等,都可以满足你所有需要同传的场景需求,线上线下通用,扫除语言障碍,让全世界的语言交流不再有国界。