Flutter动画登录界面插件animated_login的使用

Flutter动画登录界面插件animated_login的使用

概述

Animated Login 是一个为Flutter准备的现成的登录/注册屏幕,带有柔和且令人愉悦的动画。它完全响应式设计,可以在Web和移动端应用中使用。你可以用这个美丽的动画屏幕迎接用户,并提供登录和注册功能。

作者

Bahrican Yesil

示例视频

Web端示例

Web View

移动端示例

Mobile View

安装

安装说明请参考 这里

配置隐私政策链接 - URL launcher

iOS

Info.plist 文件中添加URL方案:

<key>LSApplicationQueriesSchemes</key>
<array>
  <string>sms</string>
  <string>tel</string>
</array>

Android

AndroidManifest.xml 文件中添加URL方案:

<queries>
  <intent>
    <action android:name="android.intent.action.VIEW" />
    <data android:scheme="sms" />
  </intent>
  <intent>
    <action android:name="android.intent.action.VIEW" />
    <data android:scheme="tel" />
  </intent>
</queries>

参考文档

属性列表

Property Type Description
onSignup SignupCallback 注册按钮点击后的回调
onLogin LoginCallback 登录按钮点击后的回调
socialLogins List<SocialLogin> 社交登录选项
loginTexts LoginTexts 界面上所有文本的定义
loginDesktopTheme LoginViewTheme 桌面视图的主题设置
loginMobileTheme LoginViewTheme 移动端视图的主题设置
onForgotPassword ForgotPasswordCallback 忘记密码点击后的回调
formKey GlobalKey<FormState> 自定义表单键(可选)
checkError bool 是否处理错误并显示错误信息
showForgotPassword bool 是否启用忘记密码选项
showChangeActionTitle bool 是否显示切换动作标题
showPasswordVisibility bool 是否允许用户显示密码文本
nameValidator ValidatorModel 名称字段的自定义验证器
emailValidator ValidatorModel 邮箱字段的自定义验证器
passwordValidator ValidatorModel 密码字段的自定义验证器
validateName bool 是否验证名称字段
validateEmail bool 是否验证邮箱字段
validatePassword bool 是否验证密码字段
nameController TextEditingController 名称输入字段的控制器(可选)
emailController TextEditingController 邮箱输入字段的控制器(可选)
passwordController TextEditingController 密码输入字段的控制器(可选)
confirmPasswordController TextEditingController 确认密码输入字段的控制器(可选)
backgroundImage String 欢迎部分背景图片的完整资产路径
logo Widget 显示logo的自定义小部件
signUpMode SignUpModes 确定应显示哪些文本字段:名称 / 确认密码 / 两者
languageOptions List<LanguageOption> 用户可以选择的语言列表
changeLanguageCallback ChangeLanguageCallback 语言选择后的回调
selectedLanguage LanguageOption 已存储的选定语言
changeLangOnPressed ChangeLangOnPressedCallback 点击更改语言按钮时调用的函数

完整示例代码

import 'package:animated_login/animated_login.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Animated Login',
      theme: ThemeData(
        primaryColor: Colors.blue,
        colorScheme: const ColorScheme.light(primary: Colors.blue),
        textTheme: Theme.of(context).textTheme.apply(decorationColor: Colors.blue),
        inputDecorationTheme: const InputDecorationTheme(
          prefixIconColor: Colors.black54,
          suffixIconColor: Colors.black54,
          iconColor: Colors.black54,
          labelStyle: TextStyle(color: Colors.black54),
          hintStyle: TextStyle(color: Colors.black54),
        ),
      ),
      debugShowCheckedModeBanner: false,
      initialRoute: '/login',
      routes: {
        '/login': (BuildContext context) => const LoginScreen(),
        '/forgotPass': (BuildContext context) => const ForgotPasswordScreen(),
      },
    );
  }
}

class LoginScreen extends StatefulWidget {
  const LoginScreen({Key? key}) : super(key: key);

  @override
  State<LoginScreen> createState() => _LoginScreenState();
}

class _LoginScreenState extends State<LoginScreen> {
  LanguageOption language = _languageOptions[1];
  AuthMode currentMode = AuthMode.login;
  CancelableOperation? _operation;

  @override
  Widget build(BuildContext context) {
    return AnimatedLogin(
      onLogin: (LoginData data) async => _authOperation(LoginFunctions(context).onLogin(data)),
      onSignup: (SignUpData data) async => _authOperation(LoginFunctions(context).onSignup(data)),
      onForgotPassword: _onForgotPassword,
      logo: Image.asset('assets/images/logo.gif'),
      signUpMode: SignUpModes.both,
      socialLogins: _socialLogins(context),
      loginDesktopTheme: _desktopTheme,
      loginMobileTheme: _mobileTheme,
      loginTexts: _loginTexts,
      emailValidator: ValidatorModel(
          validatorCallback: (String? email) => 'What an email! $email'),
      changeLanguageCallback: (LanguageOption? _language) {
        if (_language != null) {
          DialogBuilder(context).showResultDialog(
              'Successfully changed the language to: ${_language.value}.');
          if (mounted) setState(() => language = _language);
        }
      },
      changeLangDefaultOnPressed: () async => _operation?.cancel(),
      languageOptions: _languageOptions,
      selectedLanguage: language,
      initialMode: currentMode,
      onAuthModeChange: (AuthMode newMode) async {
        currentMode = newMode;
        await _operation?.cancel();
      },
    );
  }

  Future<String?> _authOperation(Future<String?> func) async {
    await _operation?.cancel();
    _operation = CancelableOperation.fromFuture(func);
    final String? res = await _operation?.valueOrCancellation();
    if (_operation?.isCompleted == true) {
      DialogBuilder(context).showResultDialog(res ?? 'Successful.');
    }
    return res;
  }

  Future<String?> _onForgotPassword(String email) async {
    await _operation?.cancel();
    return await LoginFunctions(context).onForgotPassword(email);
  }

  static List<LanguageOption> get _languageOptions => const <LanguageOption>[
        LanguageOption(
          value: 'Turkish',
          code: 'TR',
          iconPath: 'assets/images/tr.png',
        ),
        LanguageOption(
          value: 'English',
          code: 'EN',
          iconPath: 'assets/images/en.png',
        ),
      ];

  LoginViewTheme get _desktopTheme => _mobileTheme.copyWith(
        actionButtonStyle: ButtonStyle(
          foregroundColor: MaterialStateProperty.all(Colors.white),
        ),
        dialogTheme: const AnimatedDialogTheme(
          languageDialogTheme: LanguageDialogTheme(optionMargin: EdgeInsets.symmetric(horizontal: 80)),
        ),
        loadingSocialButtonColor: Colors.blue,
        loadingButtonColor: Colors.white,
        privacyPolicyStyle: const TextStyle(color: Colors.black87),
        privacyPolicyLinkStyle: const TextStyle(color: Colors.blue, decoration: TextDecoration.underline),
      );

  LoginViewTheme get _mobileTheme => LoginViewTheme(
        backgroundColor: Colors.blue,
        formFieldBackgroundColor: Colors.white,
        formWidthRatio: 60,
        actionButtonStyle: ButtonStyle(
          foregroundColor: MaterialStateProperty.all(Colors.blue),
        ),
        animatedComponentOrder: const <AnimatedComponent>[
          AnimatedComponent(component: LoginComponents.logo, animationType: AnimationType.right),
          AnimatedComponent(component: LoginComponents.title),
          AnimatedComponent(component: LoginComponents.description),
          AnimatedComponent(component: LoginComponents.formTitle),
          AnimatedComponent(component: LoginComponents.socialLogins),
          AnimatedComponent(component: LoginComponents.useEmail),
          AnimatedComponent(component: LoginComponents.form),
          AnimatedComponent(component: LoginComponents.notHaveAnAccount),
          AnimatedComponent(component: LoginComponents.forgotPassword),
          AnimatedComponent(component: LoginComponents.policyCheckbox),
          AnimatedComponent(component: LoginComponents.changeActionButton),
          AnimatedComponent(component: LoginComponents.actionButton),
        ],
        privacyPolicyStyle: const TextStyle(color: Colors.white70),
        privacyPolicyLinkStyle: const TextStyle(color: Colors.white, decoration: TextDecoration.underline),
      );

  LoginTexts get _loginTexts => LoginTexts(
        nameHint: _username,
        login: _login,
        signUp: _signup,
      );

  String get _username => language.code == 'TR' ? 'Kullanıcı Adı' : 'Username';
  String get _login => language.code == 'TR' ? 'Giriş Yap' : 'Login';
  String get _signup => language.code == 'TR' ? 'Kayıt Ol' : 'Sign Up';

  List<SocialLogin> _socialLogins(BuildContext context) => <SocialLogin>[
        SocialLogin(callback: () async => _socialCallback('Google'), iconPath: 'assets/images/google.png'),
        SocialLogin(callback: () async => _socialCallback('Facebook'), iconPath: 'assets/images/facebook.png'),
        SocialLogin(callback: () async => _socialCallback('LinkedIn'), iconPath: 'assets/images/linkedin.png'),
      ];

  Future<String?> _socialCallback(String type) async {
    await _operation?.cancel();
    _operation = CancelableOperation.fromFuture(LoginFunctions(context).socialLogin(type));
    final String? res = await _operation?.valueOrCancellation();
    if (_operation?.isCompleted == true && res == null) {
      DialogBuilder(context).showResultDialog('Successfully logged in with $type.');
    }
    return res;
  }
}

class ForgotPasswordScreen extends StatelessWidget {
  const ForgotPasswordScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      body: Center(
        child: Text('FORGOT PASSWORD'),
      ),
    );
  }
}

更多截图

Web 登录 移动端 登录
Web Login Mobile Login
Web 注册 移动端 注册
Web Sign Up Mobile Sign Up
颜色变化 无社交登录
Color Change Without Social Logins
错误示例
Error Example

贡献

贡献对于本项目非常重要。如果你有时间推动包的发展,我将非常感激。有关问题、错误报告、问题、功能请求、拉取请求等,请先参阅 贡献指南

如果你喜欢并受益于这个包,请在GitHub上给我们 加星,并在pub.dev上 点赞以帮助我们!

许可证

MIT License


更多关于Flutter动画登录界面插件animated_login的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter动画登录界面插件animated_login的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个使用 animated_login 插件创建 Flutter 动画登录界面的示例代码。这个插件可以帮助你快速实现一个带有动画效果的登录界面。

首先,确保你已经在 pubspec.yaml 文件中添加了 animated_login 依赖:

dependencies:
  flutter:
    sdk: flutter
  animated_login: ^x.y.z  # 请替换为最新版本号

然后,运行 flutter pub get 来获取依赖。

接下来是示例代码,展示如何使用 animated_login 插件:

import 'package:flutter/material.dart';
import 'package:animated_login/animated_login.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Animated Login Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: AnimatedLoginScreen(),
    );
  }
}

class AnimatedLoginScreen extends StatefulWidget {
  @override
  _AnimatedLoginScreenState createState() => _AnimatedLoginScreenState();
}

class _AnimatedLoginScreenState extends State<AnimatedLoginScreen> {
  final _formKey = GlobalKey<FormState>();
  String _email = '';
  String _password = '';

  void _submit() {
    if (_formKey.currentState!.validate()) {
      _formKey.currentState!.save();
      // 在这里处理登录逻辑,比如发送到服务器
      print('Email: $_email');
      print('Password: $_password');
      
      // 假设登录成功,显示一个简单的Snackbar
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('登录成功!')),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Animated Login Demo'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: AnimatedLogin(
          title: '登录',
          subTitle: '请输入您的信息',
          image: Image.asset('assets/logo.png'),  // 替换为你的图片资源
          form: Form(
            key: _formKey,
            child: Column(
              children: [
                TextFormField(
                  decoration: InputDecoration(labelText: 'Email'),
                  validator: (value) {
                    if (value == null || value.isEmpty || !value.contains('@')) {
                      return '请输入有效的电子邮件地址';
                    }
                    return null;
                  },
                  onSaved: (value) {
                    _email = value!;
                  },
                ),
                SizedBox(height: 16),
                TextFormField(
                  decoration: InputDecoration(labelText: '密码'),
                  validator: (value) {
                    if (value == null || value.isEmpty || value.length < 6) {
                      return '密码至少6个字符';
                    }
                    return null;
                  },
                  obscureText: true,
                  onSaved: (value) {
                    _password = value!;
                  },
                ),
                SizedBox(height: 24),
                AnimatedLoginButton(
                  onPressed: _submit,
                  child: Text('登录'),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

注意事项

  1. 图片资源:确保在 assets 文件夹中有 logo.png 或替换为你自己的图片资源,并在 pubspec.yaml 中声明该资源。
  2. 依赖版本:确保 animated_login 插件的版本号是最新的,以避免兼容性问题。
  3. 表单验证:示例中包含了基本的表单验证逻辑,你可以根据需求进一步扩展。

这个示例展示了如何使用 animated_login 插件创建一个带有动画效果的登录界面,并包含基本的表单验证和登录提交逻辑。希望这对你有所帮助!

回到顶部