form_builder 0.1.0 copy "form_builder: ^0.1.0" to clipboard
form_builder: ^0.1.0 copied to clipboard

outdated

flutter form builder, used to quickly build a row-column based form

example/main.dart

import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:form_builder/form_builder.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      localizationsDelegates: [
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
      ],
      theme: ThemeData(
          backgroundColor: Colors.white,
          primarySwatch: Colors.blue,
          checkboxTheme: CheckboxThemeData()
              .copyWith(checkColor: MaterialStateProperty.all(Colors.red)),
          inputDecorationTheme: InputDecorationTheme().copyWith()),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, required this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int i = 1;

  FormManagement formManagement = FormManagement();
  FormManagement formManagement2 = FormManagement();

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance!.addPostFrameCallback((timeStamp) {
      formManagement2.newFormFieldManagementByPosition(0, 1).focusListener =
          (key, hasFocus) {
        if (key == null) print('username focus changed:$hasFocus');
      };
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: SingleChildScrollView(
          child: Column(children: [
            Padding(
              padding: EdgeInsets.symmetric(horizontal: 20),
              child: Text(
                'form1',
                style: TextStyle(fontSize: 30),
              ),
            ),
            Padding(
              padding: EdgeInsets.symmetric(horizontal: 20),
              child: createForm(),
            ),
            createButtons(),
            Padding(
              padding: EdgeInsets.symmetric(horizontal: 20),
              child: createForm2(),
            ),
            createButtons2(),
          ]),
        ));
  }

  Widget createButtons() {
    Wrap buttons = Wrap(
      children: [
        Builder(
          builder: (context) {
            return TextButton(
                onPressed: () {
                  formManagement.visible = !formManagement.visible;
                  (context as Element).markNeedsBuild();
                },
                child:
                    Text(formManagement.visible ? 'hide form' : 'show form'));
          },
        ),
        Builder(
          builder: (context) {
            return TextButton(
                onPressed: () {
                  formManagement.readOnly = !formManagement.readOnly;
                  (context as Element).markNeedsBuild();
                },
                child: Text(formManagement.readOnly
                    ? 'set form editable'
                    : 'set form readonly'));
          },
        ),
        Builder(
          builder: (context) {
            FormFieldManagement username =
                formManagement.newFormFieldManagement('username');
            return TextButton(
                onPressed: () {
                  username.visible = !username.visible;
                  (context as Element).markNeedsBuild();
                },
                child:
                    Text(username.visible ? 'hide username' : 'show username'));
          },
        ),
        Builder(
          builder: (context) {
            FormFieldManagement username =
                formManagement.newFormFieldManagement('username');
            return TextButton(
                onPressed: () {
                  username.readOnly = !username.readOnly;
                  (context as Element).markNeedsBuild();
                },
                child: Text(username.readOnly
                    ? 'set username editable'
                    : 'set username readonly'));
          },
        ),
        TextButton(
            onPressed: () {
              setState(() {});
            },
            child: Text('rebuild page')),
        TextButton(
            onPressed: () {
              formManagement.validate();
              formManagement.getFocusableInvalidFields().forEach((element) {
                print(element.errorText);
              });
            },
            child: Text('validate')),
        TextButton(
            onPressed: () {
              formManagement
                  .newFormFieldManagement('username')
                  .valueFieldManagement
                  .validate();
            },
            child: Text('validate username only')),
        TextButton(
            onPressed: () {
              formManagement.reset();
            },
            child: Text('reset')),
        TextButton(
            onPressed: () {
              formManagement.newFormFieldManagement('age').focus = true;
            },
            child: Text('age focus')),
        TextButton(
            onPressed: () {
              formManagement.newFormFieldManagement('username').update({
                'labelText': DateTime.now().toString(),
              });
            },
            child: Text('change username\'s label')),
        TextButton(
            onPressed: () {
              formManagement
                  .newFormFieldManagement('age')
                  .textSelectionManagement
                  .setSelection(1, 1);
            },
            child: Text('set age\'s selection')),
        TextButton(
          onPressed: () {
            print(formManagement.data);
          },
          child: Text('get form data'),
        ),
        TextButton(
          onPressed: () {
            formManagement
                .newFormFieldManagement('button')
                .update({'label': 'new Text'});
          },
          child: Text('set button text'),
        ),
        TextButton(
          onPressed: () {
            formManagement.formThemeData = (++i) % 2 == 0
                ? FormThemeData(themeData: Theme.of(context))
                : FormThemeData.defaultTheme;
          },
          child: Text('change theme'),
        ),
        Row(children: [
          Padding(
            padding: EdgeInsets.symmetric(horizontal: 20),
            child: Text(
              'form2',
              style: TextStyle(fontSize: 30),
            ),
          ),
        ])
      ],
    );
    return buttons;
  }

  static Row createRow(String key, String value) {
    return Row(
      children: [
        Expanded(child: Text(key)),
        Spacer(),
        Expanded(child: Text(value))
      ],
    );
  }

  Widget createForm2() {
    return FormBuilder(
      formManagement: formManagement2,
      enableLayoutManagement: true,
    )
        .field(field: Label('username'), flex: 2, inline: true)
        .textField(
            hintText: 'username',
            flex: 3,
            autovalidateMode: AutovalidateMode.always,
            clearable: true)
        .nextLine()
        .field(field: Label('password'), flex: 2, inline: true)
        .textField(
            controlKey: 'password',
            hintText: 'password',
            flex: 3,
            obscureText: true,
            passwordVisible: true,
            clearable: true)
        .nextLine()
        .field(field: Label('rememberMe'), flex: 2, inline: true)
        .switchInline(
            controlKey: 'rememberMe',
            flex: 3,
            initialValue: true,
            padding: EdgeInsets.symmetric(vertical: 10))
        .nextLine()
        .divider(padding: EdgeInsets.only(top: 10, bottom: 10))
        .field(field: Label('sex'), flex: 2, inline: true)
        .checkboxGroup(
          items: FormBuilder.toCheckboxGroupItems(['male', 'female'],
              padding: EdgeInsets.symmetric(horizontal: 4)),
          inline: true,
          flex: 3,
        )
        .nextLine()
        .divider(padding: EdgeInsets.only(top: 10))
        .field(field: Label('habbit'), flex: 2, inline: true)
        .switchGroup(
            hasSelectAllSwitch: false,
            controlKey: 'habbit',
            items: FormBuilder.toSwitchGroupItems(['sport', 'film', 'sleep']),
            padding: EdgeInsets.only(top: 2, bottom: 2),
            inline: true,
            flex: 3)
        .divider(padding: EdgeInsets.only(top: 10, bottom: 10))
        .nextLine()
        .field(field: Label('age'), flex: 2, inline: true)
        .slider(
          inline: true,
          flex: 3,
          controlKey: 'age',
          max: 100,
          min: 14,
          padding: EdgeInsets.symmetric(horizontal: 4),
          subLabelRender: (value) => Text(value.round().toString()),
        )
        .field(
          field: Button(),
          flex: 1,
          inline: false,
        );
  }

  Widget createButtons2() {
    return Wrap(
      children: [
        TextButton(
            onPressed: () {
              formManagement2.newFormFieldManagementByPosition(0, 0).update({
                'label': '123',
              });
            },
            child: Text('change label at position 0,0')),
        TextButton(
            onPressed: () {
              formManagement2
                  .newFormFieldManagementByPosition(0, 1)
                  .valueFieldManagement
                  .value = 'hello world';
            },
            child: Text('set value at position 0,1')),
        Builder(
          builder: (context) {
            FormRowManagement row = formManagement2.newFormRowManagement(0);
            return TextButton(
                onPressed: () {
                  row.visible = !row.visible;
                  (context as Element).markNeedsBuild();
                },
                child: Text(row.visible ? 'hide first row' : 'show first row'));
          },
        ),
        TextButton(
            onPressed: () {
              formManagement2.newFormRowManagement(0).readOnly = true;
            },
            child: Text('set first row readonly')),
        TextButton(
            onPressed: () {
              FormLayoutManagement formLayoutManagement =
                  formManagement2.newFormLayoutManagement();
              formLayoutManagement.startEdit();
              formLayoutManagement.swapRow(0, 1);
              formLayoutManagement.apply();
            },
            child: Text('swap first row and second row')),
        TextButton(
            onPressed: () {
              FormLayoutManagement formLayoutManagement =
                  formManagement2.newFormLayoutManagement();

              if (!formManagement2.hasControlKey('num0')) {
                formLayoutManagement.startEdit();
                for (int i = 0; i <= 10; i++) {
                  int row = formLayoutManagement.rows - 1;
                  formLayoutManagement.insert(
                      row: row,
                      field: Label("new row"),
                      inline: true,
                      flex: 2,
                      insertRow: true);
                  formLayoutManagement.insert(
                      row: row,
                      inline: true,
                      flex: 3,
                      field: NumberFormField(
                        initialValue: i,
                      ),
                      controlKey: 'num$i');
                }
                formLayoutManagement.apply();
              }
            },
            child: Text('append 10 numberfield rows before apply button')),
        TextButton(
            onPressed: () {
              FormLayoutManagement formLayoutManagement =
                  formManagement2.newFormLayoutManagement();
              formLayoutManagement.startEdit();
              int rows = formLayoutManagement.rows;
              if (rows >= 2) {
                formLayoutManagement.remove(rows - 2);
              }
              if (rows != formLayoutManagement.rows)
                formLayoutManagement.apply();
              else
                formLayoutManagement.cancel();
            },
            child: Text('delete last row before apply button')),
      ],
    );
  }

  Widget createForm() {
    return FormBuilder(
      formManagement: formManagement,
    )
        .textField(
          controlKey: 'username',
          labelText: 'username',
          clearable: true,
          selectAllOnFocus: true,
          validator: (value) =>
              value.isEmpty ? 'username can not be empty !' : null,
        )
        .switchInline(
          controlKey: 'switch1',
          onChanged: (value) => print('switch1 value changed $value'),
        )
        .nextLine()
        .textField(
            controlKey: 'password',
            hintText: 'password',
            obscureText: true,
            passwordVisible: true,
            clearable: true,
            toolbarOptions: ToolbarOptions(copy: false, paste: false),
            onChanged: (value) => print('password value changed $value'),
            flex: 1)
        .textButton(
            onPressed: () {
              formManagement
                  .newFormFieldManagement('password')
                  .textSelectionManagement
                  .selectAll();
            },
            label: 'button',
            controlKey: 'button')
        .nextLine()
        .numberField(
          controlKey: 'age',
          hintText: 'age',
          clearable: true,
          flex: 3,
          min: -18,
          max: 99,
          decimal: 0,
          onChanged: (value) => print('age value changed $value'),
          validator: (value) => value == null ? 'not empty' : null,
        )
        .checkboxGroup(
          items: FormBuilder.toCheckboxGroupItems(['male', 'female']),
          controlKey: 'checkbox',
          split: 2,
          label: 'sex',
          onChanged: (value) => print('checkbox value changed $value'),
          validator: (value) => value.isEmpty ? 'pls select sex' : null,
        )
        .checkboxGroup(
          items: FormBuilder.toCheckboxGroupItems(['male', 'female']),
          split: 1,
          label: 'checkboxlisttile',
          onChanged: (value) => print('checkbox value changed $value'),
          validator: (value) => value.isEmpty ? 'pls select sex' : null,
        )
        .divider()
        .radioGroup(
          items: FormBuilder.toRadioGroupItems(['1', '2']),
          controlKey: 'radio',
          onChanged: (value) => print('radio value changed $value'),
          label: 'single choice',
          validator: (value) => value == null ? 'select one !' : null,
        )
        .radioGroup<String>(
          split: 1,
          items: FormBuilder.toRadioGroupItems(['1', '2']),
          onChanged: (value) => print('radio value changed $value'),
          label: 'radiolisttile',
          validator: (value) => value == null ? 'select one !' : null,
        )
        .divider()
        .nextLine()
        .datetimeField(
          controlKey: 'startTime',
          useTime: true,
          hintText: 'startTime',
          onChanged: (value) => print('startTime value changed $value'),
          validator: (value) => value == null ? 'not empty1' : null,
        )
        .datetimeField(
          controlKey: 'endTime',
          useTime: true,
          hintText: 'endTime',
          onChanged: (value) => print('endTime value changed $value'),
          validator: (value) => value == null ? 'not empty2' : null,
        )
        .nextLine()
        .textField(
            controlKey: 'remark',
            hintText: 'remark',
            maxLines: 5,
            flex: 1,
            clearable: true,
            onChanged: (value) => print('remark value changed $value'),
            maxLength: 500)
        .selector<int>(
            controlKey: 'selector',
            labelText: 'selector',
            multi: true,
            selectItemProvider: (page, params) {
              RangeValues filter = params['filter'];
              print(filter);
              List<int> items = List<int>.generate(100, (i) => i + 1)
                  .where((element) =>
                      element >= filter.start.round() &&
                      element <= filter.end.round())
                  .toList();
              return Future.delayed(Duration(seconds: 1), () {
                return SelectItemPage<int>(
                    items.sublist((page - 1) * 20,
                        page * 20 > items.length ? items.length : page * 20),
                    items.length);
              });
            },
            queryFormBuilder: (builder, query) {
              builder
                  .rangeSlider(
                      controlKey: 'filter',
                      min: 1,
                      max: 100,
                      inline: true,
                      rangeSubLabelRender: RangeSubLabelRender(
                          (start) => Text(start.round().toString()),
                          (end) => Text(end.round().toString())))
                  .textButton(onPressed: query, label: 'query');
            },
            onSelectDialogShow: (formManagement) {
              //use this formManagement to control query form on search dialog
              formManagement
                  .newFormFieldManagement('filter')
                  .valueFieldManagement
                  .setValue(RangeValues(20, 50));
              return true; //return true will set params before query
            },
            selectedItemLayoutType: SelectedItemLayoutType.scroll,
            onChanged: (value) => print('selector value changed $value'),
            validator: (value) => value.isEmpty ? 'select something !' : null)
        .switchGroup(
            controlKey: 'switchGroup',
            label: 'switch',
            onChanged: (value) => print('switchGroup value changed $value'),
            validator: (value) => value.isEmpty ? 'select one pls !' : null,
            selectAllPadding: EdgeInsets.only(right: 8),
            items: List<SwitchGroupItem>.generate(
                3,
                (index) => SwitchGroupItem(index.toString(),
                    padding: EdgeInsets.symmetric(vertical: 4, horizontal: 8))))
        .slider(
          controlKey: 'slider',
          min: 0,
          max: 100,
          label: 'age slider',
          validator: (value) =>
              value < 50 ? 'age slider must bigger than 50' : null,
          subLabelRender: (value) => Text(value.toStringAsFixed(0)),
          onChanged: (value) =>
              print('age slider value changed ' + value.toStringAsFixed(0)),
        )
        .numberField(
            controlKey: 'sliderInlineText',
            min: 0,
            max: 100,
            labelText: 'inline slider',
            flex: 2,
            onChanged: (v) => formManagement
                .newFormFieldManagement('sliderInline')
                .valueFieldManagement
                .setValue(v == null ? 0.0 : v.toDouble(), trigger: false))
        .slider(
            controlKey: 'sliderInline',
            min: 0,
            max: 100,
            inline: true,
            onChanged: (v) {
              formManagement
                  .newFormFieldManagement('sliderInlineText')
                  .valueFieldManagement
                  .setValue(v.toDouble().toInt(), trigger: false);
            })
        .rangeSlider(
          controlKey: 'rangeSlider',
          min: 0,
          max: 100,
          label: 'range slider',
          rangeSubLabelRender: RangeSubLabelRender((start) {
            return Text(start.toStringAsFixed(0));
          }, (end) {
            return Text(end.toStringAsFixed(0));
          }),
          onChanged: (value) =>
              print('range slider value changed ' + value.toString()),
        )
        .filterChip<String>(
            label: 'Filter Chip',
            controlKey: 'commonField',
            onChanged: (value) => print('Filter Chip Changed: $value'),
            validator: (t) =>
                t.length < 3 ? 'at least three items  must be selected ' : null,
            items: FormBuilder.toFilterChipItems([
              'java',
              'android',
              'flutter',
              'html',
              'css',
              'javascript',
              'C#',
              'swift',
              'object-c'
            ]))
        .field(
            flex: 1,
            inline: false,
            controlKey: '123',
            field: StatelessField(builder: (context) {
              BuilderInfo info = BuilderInfo.of(context);
              return Column(
                children: [
                  ClearableTextFormField(
                    autovalidateMode: info.stateMap['autovalidateMode'],
                    validator: (t) => 'always validate',
                  ),
                  TextButton(
                      onPressed: () {
                        formManagement.newFormFieldManagement('123').update1(
                            'autovalidateMode', AutovalidateMode.always);
                      },
                      child: Text('set always validate'))
                ],
              );
            }))
        .nextLine()
        .field(
            field: StatelessField(builder: (context) {
              BuilderInfo info = BuilderInfo.of(context);
              FieldKey fieldKey = info.fieldKey;
              return Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Text(
                    'I\'m a custom field',
                    style: TextStyle(fontSize: 20),
                  ),
                  Container(
                    color: info.formThemeData.themeData.primaryColor
                        .withOpacity(0.3),
                    child: ListView(
                      shrinkWrap: true,
                      children: [
                        createRow('row', '${fieldKey.row}'),
                        createRow('column', '${fieldKey.column}'),
                        createRow('controlKey', '${fieldKey.controlKey ?? ''}'),
                        createRow('flex', '${info.flex}'),
                        createRow('inline', '${info.inline}'),
                        createRow('readOnly', '${info.readOnly}'),
                      ],
                    ),
                  )
                ],
              );
            }),
            flex: 2,
            inline: false);
  }
}

class Label extends CommonField {
  final String label;
  Label(this.label)
      : super(
          {'label': TypedValue<String>(label)},
          builder: (state, stateMap, readOnly, formThemeData) {
            return Text(
              stateMap['label'],
              style: TextStyle(
                  fontSize: 18, color: formThemeData.themeData.primaryColor),
            );
          },
        );
}

class Button extends CommonField {
  Button()
      : super(
          {},
          builder: (state, stateMap, readOnly, formThemeData) {
            return Padding(
              padding: const EdgeInsets.only(
                  left: 16, right: 16, bottom: 16, top: 8),
              child: Container(
                height: 48,
                decoration: BoxDecoration(
                  color: formThemeData.themeData.primaryColor,
                  borderRadius: const BorderRadius.all(Radius.circular(24.0)),
                  boxShadow: <BoxShadow>[
                    BoxShadow(
                      color: Colors.grey.withOpacity(0.6),
                      blurRadius: 8,
                      offset: const Offset(4, 4),
                    ),
                  ],
                ),
                child: Material(
                  color: Colors.transparent,
                  child: InkWell(
                    borderRadius: const BorderRadius.all(Radius.circular(24.0)),
                    highlightColor: Colors.transparent,
                    onTap: () {
                      FormManagement management =
                          FormManagement.of(state.context);
                      Map<String, Widget> widgets =
                          management.data.map((key, value) => MapEntry(
                              key,
                              Row(
                                children: [
                                  Expanded(
                                    child: Text(key),
                                    flex: 1,
                                  ),
                                  Expanded(
                                    child: Text(value.toString()),
                                    flex: 1,
                                  ),
                                ],
                              )));
                      showDialog(
                          context: state.context,
                          builder: (BuildContext context) {
                            return AlertDialog(
                              content: Container(
                                width: double.maxFinite,
                                child: SingleChildScrollView(
                                  child: Column(
                                    children: List.from(widgets.values),
                                  ),
                                ),
                              ),
                            );
                          });
                    },
                    child: Center(
                      child: Text(
                        'Apply',
                        style: TextStyle(
                            fontWeight: FontWeight.w500,
                            fontSize: 18,
                            color: Colors.white),
                      ),
                    ),
                  ),
                ),
              ),
            );
          },
        );
}
1
likes
0
points
244
downloads

Publisher

unverified uploader

Weekly Downloads

flutter form builder, used to quickly build a row-column based form

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

flutter

More

Packages that depend on form_builder