Flutter表单管理插件flutter_form_bloc_allenlinli的使用

Flutter表单管理插件flutter_form_bloc_allenlinli的使用

包信息

Package Pub
form_bloc pub package
flutter_form_bloc pub package

功能介绍

flutter_form_bloc 是一个基于 BLoC 模式来管理表单状态的工具。它将表单状态与业务逻辑从用户界面中分离出来。

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

示例

维护者

示例代码

import 'dart:io';

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

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

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        inputDecorationTheme: InputDecorationTheme(
          border: OutlineInputBorder(
            borderRadius: BorderRadius.circular(20),
          ),
        ),
      ),
      builder: (context, child) {
        return FormThemeProvider(
          theme: FormTheme(
            checkboxTheme: CheckboxFieldTheme(
              canTapItemTile: true,
            ),
            radioTheme: RadioFieldTheme(
              canTapItemTile: true,
            ),
          ),
          child: child!,
        );
      },
      home: AllFieldsForm(),
    );
  }
}

class AllFieldsFormBloc extends FormBloc<String, String> {
  final text1 = TextFieldBloc();

  final boolean1 = BooleanFieldBloc();

  final boolean2 = BooleanFieldBloc();

  final select1 = SelectFieldBloc(
    items: ['Option 1', 'Option 2'],
    validators: [FieldBlocValidators.required],
  );

  final select2 = SelectFieldBloc(
    items: ['Option 1', 'Option 2'],
    validators: [FieldBlocValidators.required],
  );

  final multiSelect1 = MultiSelectFieldBloc<String, dynamic>(
    items: [
      'Option 1',
      'Option 2',
      'Option 3',
      'Option 4',
      'Option 5',
    ],
  );
  final file = InputFieldBloc<File?, String>(initialValue: null);

  final date1 = InputFieldBloc<DateTime?, Object>(initialValue: null);

  final dateAndTime1 = InputFieldBloc<DateTime?, Object>(initialValue: null);

  final time1 = InputFieldBloc<TimeOfDay?, Object>(initialValue: null);

  final double1 = InputFieldBloc<double, dynamic>(
    initialValue: 0.5,
  );

  AllFieldsFormBloc() : super(autoValidate: false) {
    addFieldBlocs(fieldBlocs: [
      text1,
      boolean1,
      boolean2,
      select1,
      select2,
      multiSelect1,
      date1,
      dateAndTime1,
      time1,
      double1,
    ]);
  }

  void addErrors() {
    text1.addFieldError('Awesome Error!');
    boolean1.addFieldError('Awesome Error!');
    boolean2.addFieldError('Awesome Error!');
    select1.addFieldError('Awesome Error!');
    select2.addFieldError('Awesome Error!');
    multiSelect1.addFieldError('Awesome Error!');
    date1.addFieldError('Awesome Error!');
    dateAndTime1.addFieldError('Awesome Error!');
    time1.addFieldError('Awesome Error!');
  }

  [@override](/user/override)
  void onSubmitting() async {
    try {
      await Future<void>.delayed(const Duration(milliseconds: 500));

      emitSuccess(canSubmitAgain: true);
    } catch (e) {
      emitFailure();
    }
  }
}

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (context) => AllFieldsFormBloc(),
      child: Builder(
        builder: (context) {
          final formBloc = BlocProvider.of<AllFieldsFormBloc>(context);

          return Scaffold(
            appBar: AppBar(title: const Text('内置小部件')),
            floatingActionButton: Column(
              mainAxisSize: MainAxisSize.min,
              children: <Widget>[
                FloatingActionButton.extended(
                  heroTag: null,
                  onPressed: formBloc.addErrors,
                  icon: const Icon(Icons.error_outline),
                  label: const Text('添加错误'),
                ),
                const SizedBox(height: 12),
                FloatingActionButton.extended(
                  heroTag: null,
                  onPressed: formBloc.submit,
                  icon: const Icon(Icons.send),
                  label: const Text('提交'),
                ),
              ],
            ),
            body: FormBlocListener<AllFieldsFormBloc, String, String>(
              onSubmitting: (context, state) {
                LoadingDialog.show(context);
              },
              onSuccess: (context, state) {
                LoadingDialog.hide(context);

                Navigator.of(context).pushReplacement(
                    MaterialPageRoute(builder: (_) => const SuccessScreen()));
              },
              onFailure: (context, state) {
                LoadingDialog.hide(context);
                ScaffoldMessenger.of(context).showSnackBar(
                    SnackBar(content: Text(state.failureResponse!)));
              },
              child: ScrollableFormBlocManager(
                formBloc: formBloc,
                child: SingleChildScrollView(
                  physics: const ClampingScrollPhysics(),
                  padding: const EdgeInsets.all(24.0),
                  child: Column(
                    children: <Widget>[
                      TextFieldBlocBuilder(
                        textFieldBloc: formBloc.text1,
                        suffixButton: SuffixButton.obscureText,
                        decoration: const InputDecoration(
                          labelText: 'TextFieldBlocBuilder',
                          prefixIcon: Icon(Icons.text_fields),
                        ),
                      ),
                      RadioButtonGroupFieldBlocBuilder<String>(
                        selectFieldBloc: formBloc.select2,
                        decoration: const InputDecoration(
                          labelText: 'RadioButtonGroupFieldBlocBuilder',
                        ),
                        groupStyle: const FlexGroupStyle(),
                        itemBuilder: (context, item) => FieldItem(
                          child: Text(item),
                        ),
                      ),
                      CheckboxGroupFieldBlocBuilder<String>(
                        multiSelectFieldBloc: formBloc.multiSelect1,
                        decoration: const InputDecoration(
                          labelText: 'CheckboxGroupFieldBlocBuilder',
                        ),
                        groupStyle: const ListGroupStyle(
                          scrollDirection: Axis.horizontal,
                          height: 64,
                        ),
                        itemBuilder: (context, item) => FieldItem(
                          child: Text(item),
                        ),
                      ),
                      DateTimeFieldBlocBuilder(
                        dateTimeFieldBloc: formBloc.date1,
                        format: DateFormat('dd-MM-yyyy'),
                        initialDate: DateTime.now(),
                        firstDate: DateTime(1900),
                        lastDate: DateTime(2100),
                        decoration: const InputDecoration(
                          labelText: 'DateTimeFieldBlocBuilder',
                          prefixIcon: Icon(Icons.calendar_today),
                          helperText: '日期',
                        ),
                      ),
                      DateTimeFieldBlocBuilder(
                        dateTimeFieldBloc: formBloc.dateAndTime1,
                        canSelectTime: true,
                        format: DateFormat('dd-MM-yyyy  hh:mm'),
                        initialDate: DateTime.now(),
                        firstDate: DateTime(1900),
                        lastDate: DateTime(2100),
                        decoration: const InputDecoration(
                          labelText: 'DateTimeFieldBlocBuilder',
                          prefixIcon: Icon(Icons.date_range),
                          helperText: '日期和时间',
                        ),
                      ),
                      TimeFieldBlocBuilder(
                        timeFieldBloc: formBloc.time1,
                        format: DateFormat('hh:mm a'),
                        initialTime: TimeOfDay.now(),
                        decoration: const InputDecoration(
                          labelText: 'TimeFieldBlocBuilder',
                          prefixIcon: Icon(Icons.access_time),
                        ),
                      ),
                      SwitchFieldBlocBuilder(
                        booleanFieldBloc: formBloc.boolean2,
                        body: const Text('SwitchFieldBlocBuilder'),
                      ),
                      DropdownFieldBlocBuilder<String>(
                        selectFieldBloc: formBloc.select1,
                        decoration: const InputDecoration(
                          labelText: 'DropdownFieldBlocBuilder',
                        ),
                        itemBuilder: (context, value) => FieldItem(
                          isEnabled: value != 'Option 1',
                          child: Text(value),
                        ),
                      ),
                      Row(
                        children: [
                          IconButton(
                            onPressed: () => formBloc.addFieldBloc(
                                fieldBloc: formBloc.select1),
                            icon: const Icon(Icons.add),
                          ),
                          IconButton(
                            onPressed: () => formBloc.removeFieldBloc(
                                fieldBloc: formBloc.select1),
                            icon: const Icon(Icons.delete),
                          ),
                        ],
                      ),
                      CheckboxFieldBlocBuilder(
                        booleanFieldBloc: formBloc.boolean1,
                        body: const Text('CheckboxFieldBlocBuilder'),
                      ),
                      CheckboxFieldBlocBuilder(
                        booleanFieldBloc: formBloc.boolean1,
                        body: const Text('CheckboxFieldBlocBuilder 后置'),
                        controlAffinity:
                            FieldBlocBuilderControlAffinity.trailing,
                      ),
                      SliderFieldBlocBuilder(
                        inputFieldBloc: formBloc.double1,
                        divisions: 10,
                        labelBuilder: (context, value) =>
                            value.toStringAsFixed(2),
                      ),
                      SliderFieldBlocBuilder(
                        inputFieldBloc: formBloc.double1,
                        divisions: 10,
                        labelBuilder: (context, value) =>
                            value.toStringAsFixed(2),
                        activeColor: Colors.red,
                        inactiveColor: Colors.green,
                      ),
                      SliderFieldBlocBuilder(
                        inputFieldBloc: formBloc.double1,
                        divisions: 10,
                        labelBuilder: (context, value) =>
                            value.toStringAsFixed(2),
                      ),
                      ChoiceChipFieldBlocBuilder<String>(
                        selectFieldBloc: formBloc.select2,
                        itemBuilder: (context, value) => ChipFieldItem(
                          label: Text(value),
                        ),
                      ),
                      FilterChipFieldBlocBuilder<String>(
                        multiSelectFieldBloc: formBloc.multiSelect1,
                        itemBuilder: (context, value) => ChipFieldItem(
                          label: Text(value),
                        ),
                      ),
                      BlocBuilder<InputFieldBloc<File?, String>,
                              InputFieldBlocState<File?, String>>(
                          bloc: formBloc.file,
                          builder: (context, state) {
                            return Container();
                          })
                    ],
                  ),
                ),
              ),
            ),
          );
        },
      ),
    );
  }
}

class LoadingDialog extends StatelessWidget {
  static void show(BuildContext context, {Key? key}) =>
      showDialog<void>(
        context: context,
        useRootNavigator: false,
        barrierDismissible: false,
        builder: (_) => LoadingDialog(key: key),
      ).then((_) => FocusScope.of(context).requestFocus(FocusNode()));

  static void hide(BuildContext context) => Navigator.pop(context);

  const LoadingDialog({Key? key}) : super(key: key);

  [@override](/user/override)
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () async => false,
      child: Center(
        child: Card(
          child: Container(
            width: 80,
            height: 80,
            padding: const EdgeInsets.all(12.0),
            child: const CircularProgressIndicator(),
          ),
        ),
      ),
    );
  }
}

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Icon(Icons.tag_faces, size: 100),
            const SizedBox(height: 10),
            const Text(
              '成功',
              style: TextStyle(fontSize: 54, color: Colors.black),
              textAlign: TextAlign.center,
            ),
            const SizedBox(height: 10),
            ElevatedButton.icon(
              onPressed: () => Navigator.of(context).pushReplacement(
                  MaterialPageRoute(builder: (_) => const AllFieldsForm())),
              icon: const Icon(Icons.replay),
              label: const Text('再次尝试'),
            ),
          ],
        ),
      ),
    );
  }
}

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

1 回复

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


flutter_form_bloc_allenlinli 是一个用于管理表单状态的 Flutter 插件,它基于 flutter_form_bloc 库,提供了更高级的功能和更简洁的 API 来处理复杂的表单逻辑。这个插件可以帮助开发者更轻松地管理表单字段的验证、状态更新、提交处理等。

安装

首先,你需要在 pubspec.yaml 文件中添加依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_form_bloc_allenlinli: ^0.1.0  # 请根据最新版本号进行更新

然后运行 flutter pub get 来安装依赖。

基本用法

1. 创建 FormBloc

FormBloc 是表单的核心管理类。你需要继承 FormBloc 并定义表单字段和验证逻辑。

import 'package:flutter_form_bloc_allenlinli/flutter_form_bloc_allenlinli.dart';

class MyFormBloc extends FormBloc<String, String> {
  final username = TextFieldBloc();
  final password = TextFieldBloc();

  MyFormBloc() {
    addFieldBlocs(fieldBlocs: [username, password]);
  }

  @override
  void onSubmitting() async {
    // 在这里处理表单提交逻辑
    emitSuccess(successResponse: 'Form submitted successfully');
  }
}

2. 创建表单 UI

使用 FormBlocBuilder 来构建表单 UI。FormBlocBuilder 会自动监听 FormBloc 的状态变化,并根据状态更新 UI。

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

class MyForm extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return FormBlocBuilder<MyFormBloc>(
      formBloc: MyFormBloc(),
      builder: (context, state) {
        return Column(
          children: <Widget>[
            TextFieldBlocBuilder(
              textFieldBloc: state.fieldBloc('username'),
              decoration: InputDecoration(labelText: 'Username'),
            ),
            TextFieldBlocBuilder(
              textFieldBloc: state.fieldBloc('password'),
              decoration: InputDecoration(labelText: 'Password'),
              obscureText: true,
            ),
            RaisedButton(
              onPressed: state.formBloc.submit,
              child: Text('Submit'),
            ),
          ],
        );
      },
    );
  }
}

3. 使用表单

在你的应用中,你可以直接使用 MyForm 组件来显示表单。

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Flutter Form Bloc Example')),
        body: MyForm(),
      ),
    );
  }
}

高级功能

1. 表单验证

你可以在 TextFieldBloc 中添加验证规则。例如,验证用户名不能为空:

final username = TextFieldBloc(
  validators: [
    FieldBlocValidators.required,
  ],
);

2. 表单提交处理

onSubmitting 方法中处理表单提交逻辑。你可以在这里执行异步操作,比如 API 调用。

@override
void onSubmitting() async {
  try {
    // 模拟 API 调用
    await Future.delayed(Duration(seconds: 2));
    emitSuccess(successResponse: 'Form submitted successfully');
  } catch (e) {
    emitFailure(failureResponse: 'Submission failed');
  }
}

3. 表单状态监听

你可以监听表单状态的变化,并根据状态显示不同的 UI。例如,在表单提交成功时显示成功消息:

FormBlocBuilder<MyFormBloc>(
  formBloc: MyFormBloc(),
  builder: (context, state) {
    if (state is FormBlocSuccess) {
      return Center(child: Text(state.successResponse));
    }
    return Column(
      children: <Widget>[
        // 表单字段
        RaisedButton(
          onPressed: state.formBloc.submit,
          child: Text('Submit'),
        ),
      ],
    );
  },
)
回到顶部