Flutter表单管理插件flutter_form_bloc_allenlinli的使用
Flutter表单管理插件flutter_form_bloc_allenlinli的使用
包信息
Package | Pub |
---|---|
form_bloc | |
flutter_form_bloc |
功能介绍
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
更多关于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'),
),
],
);
},
)