Flutter表单管理插件form_bloc_allenlinli的使用

Flutter表单管理插件form_bloc_allenlinli的使用

form_bloc_allenlinli 是一个用于简化表单状态管理的 Flutter 插件。它利用 BLoC 模式将表单状态与业务逻辑从用户界面中分离出来。

包信息

包名 Pub
form_bloc pub package
flutter_form_bloc pub package

特性

  • 同步字段验证
  • 异步字段验证
  • 简易加载和初始化
  • 向导/分段表单
  • 提交进度
  • 成功/失败响应
  • 可序列化表单
  • 提交错误到字段
  • 动态字段
  • 条件字段
  • 列表字段
  • 组字段
  • 增删改查支持
  • 美观的内置控件

示例

以下是 form_bloc_allenlinli 的基本使用示例:

import 'package:flutter/material.dart';
import 'package:form_bloc_allenlinli/form_bloc.dart';

// 定义登录表单的 Bloc
class LoginFormBloc extends FormBloc<String, String> {
  // 定义邮箱字段
  final email = TextFieldBloc<dynamic>(
    validators: [
      FieldBlocValidators.required,
      FieldBlocValidators.email,
    ],
  );

  // 定义密码字段
  final password = TextFieldBloc<dynamic>(
    validators: [
      FieldBlocValidators.required,
    ],
  );

  // 初始化表单字段
  LoginFormBloc() {
    addFieldBlocs(
      fieldBlocs: [
        email,
        password,
      ],
    );
  }

  // 当表单提交时调用此方法
  [@override](/user/override)
  void onSubmitting() {
    // 打印输入的邮箱和密码值
    print(email.value);
    print(password.value);
  }
}

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Form Bloc Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  [@override](/user/override)
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  // 创建 LoginFormBloc 实例
  final loginFormBloc = LoginFormBloc();

  [@override](/user/override)
  void dispose() {
    // 在组件销毁时释放资源
    loginFormBloc.dispose();
    super.dispose();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Form Bloc Example'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: <Widget>[
            // 显示表单字段
            TextFieldBlocBuilder(
              textFieldBloc: loginFormBloc.email,
              decoration: InputDecoration(
                labelText: 'Email',
                prefixIcon: Icon(Icons.email),
              ),
            ),
            TextFieldBlocBuilder(
              textFieldBloc: loginFormBloc.password,
              decoration: InputDecoration(
                labelText: 'Password',
                prefixIcon: Icon(Icons.lock),
                suffixIcon: IconButton(
                  icon: Icon(loginFormBloc.password.isHidden ? Icons.visibility : Icons.visibility_off),
                  onPressed: () {
                    loginFormBloc.password.isHidden = !loginFormBloc.password.isHidden;
                  },
                ),
              ),
              obscureText: true,
            ),
            SizedBox(height: 20),
            // 提交按钮
            RaisedButton(
              onPressed: () {
                // 提交表单
                loginFormBloc.submit();
              },
              child: Text('Submit'),
            ),
            // 显示表单状态
            StreamBuilder<bool>(
              stream: loginFormBloc.isSubmitting,
              initialData: false,
              builder: (context, snapshot) {
                return Visibility(
                  visible: snapshot.data,
                  child: CircularProgressIndicator(),
                );
              },
            ),
            // 显示提交结果
            StreamBuilder(
              stream: loginFormBloc.submissionStatus,
              builder: (context, snapshot) {
                if (snapshot.hasData && snapshot.data is SubmissionSuccess) {
                  return Text('Success');
                } else if (snapshot.hasData && snapshot.data is SubmissionFailure) {
                  return Text('Failed');
                }
                return Container();
              },
            ),
          ],
        ),
      ),
    );
  }
}

更多关于Flutter表单管理插件form_bloc_allenlinli的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter表单管理插件form_bloc_allenlinli的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何使用 form_bloc_allenlinli 插件来管理 Flutter 表单的示例代码。这个插件允许你使用 BLoC 模式来管理表单状态,从而提高代码的可维护性和可测试性。

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

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

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

接下来,我们创建一个简单的表单示例,其中包括用户名和密码字段,并使用 form_bloc 来管理它们的状态。

1. 定义表单状态和数据模型

import 'package:form_bloc/form_bloc.dart';

// 表单字段状态
enum FormFieldStatus { initial, dirty, valid, invalid }

// 表单字段数据模型
class FormField<T> {
  final String key;
  T value;
  FormFieldStatus status;
  String? errorMessage;

  FormField({required this.key, required this.value, this.status = FormFieldStatus.initial, this.errorMessage});
}

// 表单数据模型
class LoginFormData {
  final String username;
  final String password;

  LoginFormData({required this.username, required this.password});
}

2. 创建表单 BLoC

import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:form_bloc/form_bloc.dart';
import 'package:equatable/equatable.dart';

part 'login_form_event.dart';
part 'login_form_state.dart';

class LoginFormBloc extends Bloc<LoginFormEvent, LoginFormState> {
  LoginFormBloc() : super(LoginFormState.initial());

  [@override](/user/override)
  Stream<LoginFormState> mapEventToState(LoginFormEvent event) async* {
    if (event is UsernameChanged) {
      yield* _mapUsernameChangedToState(event);
    } else if (event is PasswordChanged) {
      yield* _mapPasswordChangedToState(event);
    } else if (event is Submitted) {
      yield* _mapSubmittedToState(event);
    }
  }

  Stream<LoginFormState> _mapUsernameChangedToState(UsernameChanged event) async* {
    yield state.copyWith(
      username: FormField(
        key: 'username',
        value: event.username,
        status: FormFieldStatus.dirty,
        errorMessage: _validateUsername(event.username),
      ),
    );
  }

  Stream<LoginFormState> _mapPasswordChangedToState(PasswordChanged event) async* {
    yield state.copyWith(
      password: FormField(
        key: 'password',
        value: event.password,
        status: FormFieldStatus.dirty,
        errorMessage: _validatePassword(event.password),
      ),
    );
  }

  Stream<LoginFormState> _mapSubmittedToState(Submitted event) async* {
    if (state.isFormValid) {
      yield state.copyWith(status: FormStatus.submitting);
      // 在这里处理表单提交逻辑,比如调用API
      await Future.delayed(Duration(seconds: 1)); // 模拟API调用
      yield state.copyWith(status: FormStatus.success);
    } else {
      yield state.copyWith(status: FormStatus.invalid);
    }
  }

  String? _validateUsername(String value) {
    if (value.isEmpty || value.length < 3) {
      return 'Username must be at least 3 characters long.';
    }
    return null;
  }

  String? _validatePassword(String value) {
    if (value.isEmpty || value.length < 6) {
      return 'Password must be at least 6 characters long.';
    }
    return null;
  }
}

3. 定义事件和状态

login_form_event.dart

part of 'login_form_bloc.dart';

abstract class LoginFormEvent extends Equatable {
  const LoginFormEvent();
}

class UsernameChanged extends LoginFormEvent {
  final String username;
  const UsernameChanged({required this.username});

  [@override](/user/override)
  List<Object?> get props => [username];
}

class PasswordChanged extends LoginFormEvent {
  final String password;
  const PasswordChanged({required this.password});

  [@override](/user/override)
  List<Object?> get props => [password];
}

class Submitted extends LoginFormEvent {
  const Submitted();

  [@override](/user/override)
  List<Object?> get props => [];
}

login_form_state.dart

part of 'login_form_bloc.dart';

class LoginFormState extends Equatable {
  final FormField<String> username;
  final FormField<String> password;
  final FormStatus status;

  const LoginFormState({
    required this.username,
    required this.password,
    this.status = FormStatus.initial,
  });

  LoginFormState copyWith({
    FormField<String>? username,
    FormField<String>? password,
    FormStatus? status,
  }) {
    return LoginFormState(
      username: username ?? this.username,
      password: password ?? this.password,
      status: status ?? this.status,
    );
  }

  bool get isFormValid {
    return username.status == FormFieldStatus.valid && password.status == FormFieldStatus.valid;
  }

  [@override](/user/override)
  List<Object?> get props => [username, password, status];
}

enum FormStatus { initial, invalid, submitting, success }

4. 创建 Flutter UI

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:form_bloc_allenlinli/form_bloc_allenlinli.dart';
import 'login_form_bloc.dart';

void main() {
  runApp(BlocProvider<LoginFormBloc>(
    create: (context) => LoginFormBloc(),
    child: MyApp(),
  ));
}

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: LoginFormScreen(),
    );
  }
}

class LoginFormScreen extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    final LoginFormBloc formBloc = context.read<LoginFormBloc>();
    return Scaffold(
      appBar: AppBar(title: Text('Login Form')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: BlocListener<LoginFormBloc, LoginFormState>(
          listener: (context, state) {
            if (state.status == FormStatus.success) {
              ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Login Success')));
            }
          },
          child: FormBlocBuilder<LoginFormBloc, LoginFormState, LoginFormData>(
            formBloc: formBloc,
            initialData: LoginFormData(username: '', password: ''),
            builder: (context, formData, state) {
              return Column(
                children: <Widget>[
                  TextFormFieldBlocBuilder<String>(
                    formBloc: formBloc,
                    fieldKey: 'username',
                    decoration: InputDecoration(labelText: 'Username'),
                    validator: (value) => state.username.errorMessage,
                    onChanged: (value) => context.read<LoginFormBloc>().add(UsernameChanged(username: value)),
                  ),
                  TextFormFieldBlocBuilder<String>(
                    formBloc: formBloc,
                    fieldKey: 'password',
                    decoration: InputDecoration(labelText: 'Password', suffixIcon: IconButton(icon: Icon(Icons.visibility), onPressed: () {})),
                    validator: (value) => state.password.errorMessage,
                    onChanged: (value) => context.read<LoginFormBloc>().add(PasswordChanged(password: value)),
                  ),
                  SizedBox(height: 20),
                  ElevatedButton(
                    onPressed: () => context.read<LoginFormBloc>().add(Submitted()),
                    child: Text('Login'),
                  ),
                ],
              );
            },
回到顶部