Flutter自定义表单字段插件folly_fields的使用

发布于 1周前 作者 phonegap100 来自 Flutter

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

1 回复

更多关于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允许你通过传递参数来自定义字段的样式和行为。例如,你可以设置decorationtextStyle等属性。以下是一个自定义样式的示例:

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插件来创建和管理自定义表单字段。你可以根据实际需求进一步自定义字段的样式和行为。希望这对你有所帮助!

回到顶部