Flutter自定义表单字段插件folly_fields的使用
Flutter 自定义表单字段插件 folly_fields 的使用
folly_fields
是一个用于 Flutter 应用程序的自定义表单字段库。它提供了许多常用的表单字段组件,并且易于集成到你的项目中。
功能特点
- 提供了多种常用的表单字段组件,如文本输入、日期选择、布尔值等。
- 可以轻松地进行国际化和本地化。
- 支持验证器和回调函数,方便表单处理。
使用示例
1. 添加依赖
首先,在 pubspec.yaml
文件中添加 folly_fields
依赖:
dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
# https://pub.dev/packages/folly_fields
folly_fields: x.y.z # 最新的 pub.dev 发布版本
检查 pub.dev 最新发布版本。
对于边缘构建,可以替换为 GitHub 仓库:
# https://github.com/edufolly/folly_fields
folly_fields:
git:
url: https://github.com/edufolly/folly_fields.git
ref: v0.0.1 # 最新的发布版本或分支名称
使用 ref
来避免不兼容的变化。
检查 GitHub 最新发布版本。
2. 配置
创建配置文件 config.dart
,例如:
class Config extends AbstractConfig {
static final Config _singleton = Config._internal();
factory Config() {
return _singleton;
}
Config._internal();
/// 内容...
}
3. 主入口文件
在 main.dart
中初始化 folly_fields
:
import 'package:flutter/material.dart';
import 'package:folly_fields/folly_fields.dart';
import 'config.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
FollyFields.start(Config());
runApp(const MyApp());
}
4. 创建主应用
在 main.dart
中创建 MaterialApp
:
class MyApp extends StatelessWidget {
const MyApp({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
title: 'Folly Fields Example',
theme: ThemeData(
primarySwatch: Colors.deepOrange,
),
home: const MyHomePage(),
localizationsDelegates: const [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: const [
Locale('pt', 'BR'),
],
);
}
}
5. 创建表单页面
在 MyHomePage
中创建表单页面:
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
[@override](/user/override)
MyHomePageState createState() => MyHomePageState();
}
class MyHomePageState extends State<MyHomePage> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
String labelPrefix = Config().labelPrefix;
bool edit = true;
ExampleModel model = ExampleModel.generate();
List<ExampleModel> list = [];
[@override](/user/override)
Widget build(BuildContext context) {
List<MyMenuItem> menuItems = [
// 菜单项
];
return Scaffold(
appBar: AppBar(
title: Text('Folly Fields ${Config().version}'),
actions: Config().isMobile
? <PopupMenuButton<MyMenuItem>>[
PopupMenuButton<MyMenuItem>(
tooltip: 'Menu',
icon: const Icon(Icons.more_vert),
itemBuilder: (BuildContext context) => menuItems
.map<PopupMenuEntry<MyMenuItem>>(
(MyMenuItem e) => e.popupMenuItem,
)
.toList(),
onSelected: (MyMenuItem item) => item.onPressed(context),
),
]
: menuItems
.map((MyMenuItem item) => item.iconButton(context))
.toList(),
),
body: SafeArea(
child: SafeFutureBuilder<Response>(
future: get(Uri.parse(
'https://raw.githubusercontent.com/edufolly/folly_fields/main/example/lib/main.dart',
)),
builder: (BuildContext context, Response response, _) {
int statusCode = response.statusCode;
if (statusCode < 200 || statusCode > 299) {
return ErrorMessage(error: 'Status code error: $statusCode');
}
String code = response.body;
return SingleChildScrollView(
padding: const EdgeInsets.all(24),
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// 表单标题
Padding(
padding: const EdgeInsets.all(8),
child: Text(
'Formulário Básico',
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.headlineMedium,
),
),
// 字段组件
CodeLink(
code: code,
tag: 'StringField',
source: 'https://github.com/edufolly/folly_fields/blob/main/lib/fields/string_field.dart',
child: // 文本字段
StringField(
labelPrefix: labelPrefix,
label: 'Texto*',
enabled: edit,
initialValue: model.text,
validator: (String? value) =>
value == null || value.isEmpty
? 'O campo texto precisa ser informado.'
: null,
onSaved: (String? value) => model.text = value!,
),
),
CodeLink(
code: code,
tag: 'EmailField',
source: 'https://github.com/edufolly/folly_fields/blob/main/lib/fields/email_field.dart',
child: // 邮箱字段
EmailField(
labelPrefix: labelPrefix,
label: 'E-mail*',
enabled: edit,
initialValue: model.email,
onSaved: (String? value) => model.email = value ?? '',
),
),
// 其他字段组件...
// 提交按钮
Padding(
padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 8),
child: ElevatedButton.icon(
icon: const Icon(Icons.send),
label: const Text('ENVIAR'),
onPressed: _send,
),
),
],
),
),
);
},
),
),
);
}
void _send() {
if (_formKey.currentState!.validate()) {
_formKey.currentState!.save();
if (kDebugMode) {
print(model.toMap());
}
FollyDialogs.dialogMessage(
context: context,
title: 'Resultado do método toMap(). O blob é mostrado como base64.',
message: model.toMap().toString(),
);
}
}
}
完整示例代码
完整的 main.dart
示例代码如下:
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:folly_fields/fields/bool_field.dart';
import 'package:folly_fields/fields/cep_field.dart';
import 'package:folly_fields/fields/cest_field.dart';
import 'package:folly_fields/fields/choice_chip_field.dart';
import 'package:folly_fields/fields/cnae_field.dart';
import 'package:folly_fields/fields/cnpj_field.dart';
import 'package:folly_fields/fields/color_field.dart';
import 'package:folly_fields/fields/cpf_cnpj_field.dart';
import 'package:folly_fields/fields/cpf_field.dart';
import 'package:folly_fields/fields/date_field.dart';
import 'package:folly_fields/fields/date_time_field.dart';
import 'package:folly_fields/fields/decimal_field.dart';
import 'package:folly_fields/fields/dropdown_field.dart';
import 'package:folly_fields/fields/email_field.dart';
import 'package:folly_fields/fields/icon_data_field.dart';
import 'package:folly_fields/fields/integer_field.dart';
import 'package:folly_fields/fields/ipv4_field.dart';
import 'package:folly_fields/fields/licence_plate_field.dart';
import 'package:folly_fields/fields/list_field.dart';
import 'package:folly_fields/fields/local_phone_field.dart';
import 'package:folly_fields/fields/mac_address_field.dart';
import 'package:folly_fields/fields/mobile_phone_field.dart';
import 'package:folly_fields/fields/model_field.dart';
import 'package:folly_fields/fields/multiline_field.dart';
import 'package:folly_fields/fields/ncm_field.dart';
import 'package:folly_fields/fields/new_decimal_field.dart';
import 'package:folly_fields/fields/password_field.dart';
import 'package:folly_fields/fields/password_visible_field.dart';
import 'package:folly_fields/fields/phone_field.dart';
import 'package:folly_fields/fields/string_field.dart';
import 'package:folly_fields/fields/time_field.dart';
import 'package:folly_fields/folly_fields.dart';
import 'package:folly_fields/util/decimal.dart';
import 'package:folly_fields/util/folly_validators.dart';
import 'package:folly_fields/util/icon_helper.dart';
import 'package:folly_fields/util/safe_builder.dart';
import 'package:folly_fields/widgets/circular_waiting.dart';
import 'package:folly_fields/widgets/error_message.dart';
import 'package:folly_fields/widgets/folly_dialogs.dart';
import 'package:folly_fields_example/advanced/example_builder.dart';
import 'package:folly_fields_example/advanced/example_consumer.dart';
import 'package:folly_fields_example/advanced/example_edit.dart';
import 'package:folly_fields_example/advanced/example_list.dart';
import 'package:folly_fields_example/basic_table/example_basic_table.dart';
import 'package:folly_fields_example/brand_new/brand_new_builder.dart';
import 'package:folly_fields_example/brand_new/brand_new_consumer.dart';
import 'package:folly_fields_example/brand_new/brand_new_edit.dart';
import 'package:folly_fields_example/brand_new/brand_new_model.dart';
import 'package:folly_fields_example/code_link.dart';
import 'package:folly_fields_example/config.dart';
import 'package:folly_fields_example/example_enum.dart';
import 'package:folly_fields_example/example_model.dart';
import 'package:folly_fields_example/example_table.dart';
import 'package:folly_fields_example/views/credit_card.dart';
import 'package:folly_fields_example/views/four_images.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:http/http.dart';
import 'package:url_launcher/url_launcher_string.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
FollyFields.start(Config());
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Folly Fields Example',
theme: ThemeData(
colorSchemeSeed: Colors.deepOrange,
useMaterial3: true,
brightness: Brightness.dark,
),
initialRoute: '/',
routes: <String, WidgetBuilder>{
'/': (_) => const MyHomePage(),
// TODO(edufolly): This route was deprecated.
'/table': (_) => const ExampleTable(),
'/list': (_) => ExampleList(),
'/edit': (_) => ExampleEdit(
ExampleModel.generate(),
const ExampleBuilder(),
const ExampleConsumer(),
edit: true,
),
'/brandnew': (_) => BrandNewEdit(
BrandNewModel(),
const BrandNewBuilder(),
BrandNewConsumer(),
edit: true,
),
'/four_images': (_) => const FourImages(),
'/credit_card': (_) => const CreditCard(),
'/basic_table': (_) => const ExampleBasicTable(),
},
localizationsDelegates: const [
...GlobalMaterialLocalizations.delegates,
GlobalWidgetsLocalizations.delegate,
],
supportedLocales: const [
Locale('pt', 'BR'),
],
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
[@override](/user/override)
MyHomePageState createState() => MyHomePageState();
}
class MyHomePageState extends State<MyHomePage> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
String labelPrefix = Config().labelPrefix;
bool edit = true;
ExampleModel model = ExampleModel.generate();
List<ExampleModel> list = [];
[@override](/user/override)
Widget build(BuildContext context) {
List<MyMenuItem> menuItems = [
// 菜单项
];
return Scaffold(
appBar: AppBar(
title: Text('Folly Fields ${Config().version}'),
actions: Config().isMobile
? <PopupMenuButton<MyMenuItem>>[
PopupMenuButton<MyMenuItem>(
tooltip: 'Menu',
icon: const Icon(Icons.more_vert),
itemBuilder: (BuildContext context) => menuItems
.map<PopupMenuEntry<MyMenuItem>>(
(MyMenuItem e) => e.popupMenuItem,
)
.toList(),
onSelected: (MyMenuItem item) => item.onPressed(context),
),
]
: menuItems
.map((MyMenuItem item) => item.iconButton(context))
.toList(),
),
body: SafeArea(
child: SafeFutureBuilder<Response>(
future: get(Uri.parse(
'https://raw.githubusercontent.com/edufolly/folly_fields/main/example/lib/main.dart',
)),
builder: (BuildContext context, Response response, _) {
int statusCode = response.statusCode;
if (statusCode < 200 || statusCode > 299) {
return ErrorMessage(error: 'Status code error: $statusCode');
}
String code = response.body;
return SingleChildScrollView(
padding: const EdgeInsets.all(24),
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// 表单标题
Padding(
padding: const EdgeInsets.all(8),
child: Text(
'Formulário Básico',
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.headlineMedium,
),
),
// 字段组件
CodeLink(
code: code,
tag: 'StringField',
source: 'https://github.com/edufolly/folly_fields/blob/main/lib/fields/string_field.dart',
child: // 文本字段
StringField(
labelPrefix: labelPrefix,
label: 'Texto*',
enabled: edit,
initialValue: model.text,
validator: (String? value) =>
value == null || value.isEmpty
? 'O campo texto precisa ser informado.'
: null,
onSaved: (String? value) => model.text = value!,
),
),
CodeLink(
code: code,
tag: 'EmailField',
source: 'https://github.com/edufolly/folly_fields/blob/main/lib/fields/email_field.dart',
child: // 邮箱字段
EmailField(
labelPrefix: labelPrefix,
label: 'E-mail*',
enabled: edit,
initialValue: model.email,
onSaved: (String? value) => model.email = value ?? '',
),
),
// 其他字段组件...
// 提交按钮
Padding(
padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 8),
child: ElevatedButton.icon(
icon: const Icon(Icons.send),
label: const Text('ENVIAR'),
onPressed: _send,
),
),
],
),
),
);
},
),
),
);
}
void _send() {
if (_formKey.currentState!.validate()) {
_formKey.currentState!.save();
if (kDebugMode) {
print(model.toMap());
}
FollyDialogs.dialogMessage(
context: context,
title: 'Resultado do método toMap(). O blob é mostrado como base64.',
message: model.toMap().toString(),
);
}
}
}
class MyMenuItem {
final String name;
final IconData iconData;
final Function(BuildContext context) onPressed;
MyMenuItem({
required this.name,
required this.iconData,
required this.onPressed,
});
IconButton iconButton(BuildContext context) => IconButton(
icon: Icon(iconData),
onPressed: () => onPressed(context),
tooltip: name,
);
PopupMenuItem<MyMenuItem> get popupMenuItem => PopupMenuItem<MyMenuItem>(
value: this,
child: Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(right: 16),
child: Icon(iconData),
),
Text(name),
],
),
);
}
更多关于Flutter自定义表单字段插件folly_fields的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter自定义表单字段插件folly_fields的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是如何在Flutter项目中使用folly_fields
插件来自定义表单字段的示例代码。folly_fields
是一个允许你快速创建和管理复杂表单字段的插件。假设你已经在pubspec.yaml
文件中添加了folly_fields
依赖并运行了flutter pub get
。
1. 安装依赖
首先,确保你的pubspec.yaml
文件包含以下依赖:
dependencies:
flutter:
sdk: flutter
folly_fields: ^最新版本号 # 请替换为实际的最新版本号
2. 导入插件
在你的Dart文件中导入folly_fields
:
import 'package:folly_fields/folly_fields.dart';
import 'package:flutter/material.dart';
3. 创建自定义表单字段
下面是一个使用folly_fields
创建自定义表单字段的示例:
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Folly Fields Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final _formKey = GlobalKey<FormState>();
String? _name;
String? _email;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Folly Fields Demo'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
// 使用 FollyTextFormField 创建文本字段
FollyTextFormField(
labelText: 'Name',
onChanged: (value) {
setState(() {
_name = value;
});
},
validator: (value) {
if (value == null || value.isEmpty) {
return 'Name is required';
}
return null;
},
),
// 使用 FollyEmailFormField 创建电子邮件字段
FollyEmailFormField(
labelText: 'Email',
onChanged: (value) {
setState(() {
_email = value;
});
},
validator: (value) {
if (value == null || !value.contains('@')) {
return 'Please enter a valid email';
}
return null;
},
),
SizedBox(height: 20),
ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
// 如果验证通过,执行提交逻辑
print('Name: $_name');
print('Email: $_email');
}
},
child: Text('Submit'),
),
],
),
),
),
);
}
}
4. 自定义字段样式和行为
folly_fields
允许你通过传递参数来自定义字段的样式和行为。例如,你可以设置decoration
、textStyle
等属性。以下是一个自定义样式的示例:
FollyTextFormField(
labelText: 'Custom Styled Name',
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
filled: true,
fillColor: Colors.grey[200]!,
prefixIcon: Icon(Icons.person),
),
textStyle: TextStyle(fontSize: 18, color: Colors.black),
onChanged: (value) {
setState(() {
_name = value;
});
},
validator: (value) {
if (value == null || value.isEmpty) {
return 'Name is required';
}
return null;
},
),
总结
以上代码展示了如何在Flutter项目中使用folly_fields
插件来创建和管理自定义表单字段。你可以根据实际需求进一步自定义字段的样式和行为。希望这对你有所帮助!