form_builder 2.0.0-alpha2 copy "form_builder: ^2.0.0-alpha2" to clipboard
form_builder: ^2.0.0-alpha2 copied to clipboard

outdated

flutter row-column based form builder, build form quickly,create field fast,less code,more powerful

flutter_form_builder #

basic usage #

FormKey formKey = FormKey();// formkey is a global key

//if you want to create a simple formbuilder
Widget form = FormBuilder()
         .key(formKey)
        .onChanged((name, oldValue, newValue) {
          print(
              '$name\'s value changed, oldValue:$oldValue newValue:$newValue');
        }).build(child:Widget);

// if you want to create a row-column based formbuilder
Widget form = FormBuilder()
        .key(formKey)
        .onChanged((name, oldValue, newValue) {
          print(
              '$name\'s value changed, oldValue:$oldValue newValue:$newValue');
        })
        .layoutBuilder()
        .enableLayoutManagement(true)
        .oneRowField(ClearableTextFormField(
          name: 'username',
          labelText: 'username',
          clearable: true,
          onTap: () {
            print("??");
          },
          selectAllOnFocus: true,
          validator: (value) =>
              value.isEmpty ? 'username can not be empty !' : null,
        )).build();

form widget tree #

Column 
  Row
    FormField 

base field widget tree #

base field is default form field

Flexible(
  fit: state.visible ? FlexFit.tight : FlexFit.loose,
  child: Padding(
    padding: state.padding ?? const EdgeInsets.all(5),
    child: Visibility(
      maintainState: true,
      child: BaseFormField,
      visible: state.visible,
    ),
  ),
  flex: state.flex,
)

methods #

FormBuilder #

create a new row

if form layout's last row is not empty,will creat a new row

FormBuilder builder = formBuilder.newRow();

customize last row

FormBuilder builder = formBuilder.customize({
    MainAxisAlignment? mainAxisAlignment,
    MainAxisSize? mainAxisSize,
    CrossAxisAlignment? crossAxisAlignment,
    TextDirection? textDirection,
    VerticalDirection? verticalDirection,
    TextBaseline? textBaseline,
  })

append a field

append a field to last row

FormBuilder builder = formBuilder.append(Widget field);

append a builder field

FormBuilder builder = formBuilder.appendBuilder(FieldBuilder builder);

append a field take up one row

FormBuilder builder = formBuilder.oneRowField(Widget field);

append a builder field take up one row

FormBuilder builder = formBuilder.oneRowBuilder(FieldBuilder builder);

FormManagement #

whether has a name field

bool hasField => formManagement.hasField(String name);

whether form is visible

bool visible = formManagement.visible;

hide|show form

formManagement.visible = true|false;

whether form is readOnly

bool readOnly = formManagement.readOnly;

set form readonly|editable

formManagement.readOnly = true|false;

get rows of form

int rows = formManagement.rows;

get column of row

int column = formManagement.getColumn(row);

create FormFieldManagement

FormFieldManagement formFieldManagement = formManagement.newFormFieldManagement(String name);

create FormPositionManagement

FormPositionManagement formPositionManagement = formManagement.newFormPositionManagement(int row,{int? column});

create FormLayoutManagement(experimental)

FormLayoutManagement formLayoutManagement = formManagement.newFormLayoutManagement()

get form data

only contains field which has a name

Map<String,dynamic> dataMap = formManagement.data;

set form data

Map<String,dynamic> formData = {};
formManagement.data = formData;//will trigger field's onChanged
formManagement.setData(formData,{trigger:trigger});

reset form

formManagement.reset();

validate form

formManagement.validate();

whether form is valid

unlike validate method, this method won't display error msg

bool isValid = formManagement.isValid

get error

get all errors after validate

Map<String, FormFieldManagement> errorMap = formManagement.error;

quietly validate

validate all field and get error , this method will not display error msg

List<FormFieldManagementError> errors = formManagement.quietlyValidate();

FormFieldManagement #

whether field is focusable

bool focusable => formFieldManagement.focusable

whether field is focused

bool focused => formFieldManagement.hasFocus

focus|unfocus field

formFieldManagement.focus = true|false

set focuslistener

call this method in WidgetsBinding.instance!.addPostFrameCallback

formFieldManagement.focusListener = (key,hasFocus){
  // when key is null, root node focused
  // otherwise sub node focused
}

get ValueFieldManagement

field must be a valuefield ,otherwise an error will be throw

ValueFieldManagement ValueFieldManagement  = formFieldManagement.valueFieldManagement 

whether field is ValueField

bool isValueField = formFieldManagement.isValueField;

whether field support textSelection

bool supportTextSelection = formFieldManagement.supportTextSelection

get TextSelectionManagement

if field don't support textSelection ,an error will be throw

TextSelectionManagement  textSelectionManagement = formFieldManagement.textSelectionManagement

whether field is readOnly

bool readOnly = formFieldManagement.readOnly;

set readOnly

formFieldManagement.readOnly = true|false

whether field is visible

bool visible = formFieldManagement.visible;

set visible

formFieldManagement.visible = true|false

update field's state

see supported states for every field here

formFieldManagement.update({});

update one field state

see supported states for every field here

formFieldManagement.update1(String key,dynamic value);

make field visible in viewport

not work if field or form is invisible

  Future<void> future = formFieldManagement.ensureVisible(
      {Duration? duration,
      Curve? curve,
      ScrollPositionAlignmentPolicy? alignmentPolicy,
      double? alignment})

ValueFieldManagement #

get value

dynamic value => valueFieldManagement.value

set value

valueFieldManagement.value = value;//will trigger onChanged
valueFieldManagement.setValue(dynamic value,{bool trigger})

whether field is valid

this method won't display error msg

bool isValid = valueFieldManagement.isValid;

validate field

this method will display error and return whether field is valid

bool isValid = valueFieldManagement.validate();

reset field

valueFieldManagement.reset();

get error

String? error = valueFieldManagement.error;

FormPositionManagement #

whether all fields is readOnly

bool get readOnly => formPositionManagement.readOnly;

set readOnly on all fields

formPositionManagement.readOnly = true|false;

whether at least one field is visible

bool visible = formPositionManagement.visible;

set visible on all fields

formPositionManagement.visible = true|false;

FormLayoutManagement (experimental) #

whether a layout is editing

bool isEditing = formLayoutManagement.isEditing;

get rows of currrent editing layout

int rows = formLayoutManagement.rows;

get columns of a row in current editing layout

int columns = formLayoutManagement.getColumns(int row);

customize column

void customizeColumn({
    MainAxisAlignment? mainAxisAlignment,
    MainAxisSize? mainAxisSize,
    CrossAxisAlignment? crossAxisAlignment,
    TextDirection? textDirection,
    VerticalDirection? verticalDirection,
    TextBaseline? textBaseline,
  })

customize row

void customizeRow({
    int? row,
    MainAxisAlignment? mainAxisAlignment,
    MainAxisSize? mainAxisSize,
    CrossAxisAlignment? crossAxisAlignment,
    TextDirection? textDirection,
    VerticalDirection? verticalDirection,
    TextBaseline? textBaseline,
  })

remove in layout

formLayoutManagement.remove(int row,{int column});

insert field at position

void insert(
    {int? column,
    int? row, //if row is null,append after last row
    required Widget field, 
    bool newRow = false,//whether create a new row
    })

swap two rows

formLayoutManagement.swapRow(int oldRow, int newRow)

start edit current layout

you should enableLayoutFormManagement

formLayoutManagement.startEdit();

apply edited layout

formLayoutManagement.apply();

cancel editing layout

formLayoutManagement.cancel();

field states #

ClearableTextFormField #

name Type nullable
labelText String true
hintText String true
keyboardType TextInputType true
autofocus bool false
maxLines int true
minLines int true
maxLength int true
clearable bool false
prefixIcon Widget true
inputFormatters List< TextInputFormatter> true
style TextStyle true
toolbarOptions ToolbarOptions true
selectAllOnFocus bool false
suffixIcons List< Widget> true
textInputAction TextInputAction true
inputDecorationTheme InputDecorationTheme true
textCapitalization TextCapitalization true

DateTimeFormField #

name Type nullable
labelText String true
hintText String true
maxLines int false
type DateTimeType false
formatter DateTimeFormatter true
style TextStyle true
inputDecorationTheme InputDecorationTheme true
firstDate DateTime false
lastDate DateTime false

NumberFormField #

name Type nullable
labelText String true
hintText String true
autofocus bool false
clearable bool false
prefixIcon Widget true
style TextStyle true
suffixIcons List< Widget> true
textInputAction TextInputAction true
inputDecorationTheme InputDecorationTheme true
decimal int false
max double true
allowNegative bool false

SelectorFormField #

name Type nullable
labelText String true
hintText String true
multi bool false
clearable bool false
selectorThemeData SelectorThemeData false
selectedItemLayoutType SelectedItemLayoutType false

SliderFormField #

name Type nullable
labelText String true
max double false
min double false
divisions int false
activeColor Color true
inactiveColor Color true

RangeSliderFormField #

name Type nullable
labelText String true
max double false
min double false
divisions int false
activeColor Color true
inactiveColor Color true

ListTileFormField #

name Type nullable
labelText String true
split int false
items List< ListTileItem<T>> false
hasSelectAll bool false
checkboxRenderData CheckboxRenderData true
radioRenderData RadioRenderData true
switchRenderData SwitchRenderData true
listTileThemeData ListTileThemeData true

FilterChipFormField #

name Type nullable
labelText String true
items List< FilterChipItem<T>> false
pressElevation double true
count int true
layoutType ChipLayoutType false
chipThemeData ChipThemeData true

RateFormField #

name Type nullable
labelText String true
rateThemeData RateThemeData true

SingleSwitchFormField #

name Type nullable
label Widget true
switchRenderData SwitchRenderData true

SingleCheckboxFormField #

name Type nullable
label Widget true
checkboxRenderData CheckboxRenderData true

ButtonFormField #

name Type nullable
icon Widget true
child Widget false

currently support fields #

field return value nullable
ClearableTextFormField string false
DateTimeFormField DateTime true
SelectorFormField List< T> false
ListTileFormField List< T> false
InlineFormField bool false
NumberFormField num true
SliderFormField double false
RangeSliderFormField RangeValues false
FilterChipFormField List< T> false
RateFormField dobule true
SingleSwitchFormField bool false
SingleCheckboxFormField bool false
ButtonFormField - -

build your own form field #

build a value field #

if you want to build a nullable value field ,just extends BaseValueField

this is an example:

class CustomNullableValueField<T> extends BaseValueField<T> {
  CustomNullableValueField({
    String? name,//important !,used to maintain state and used as a key when you get data via FormManagement.data
    required T value,
    String? label,
    TextStyle? textStyle,
    T? initialValue,
    ValueChanged<T?>? onChanged,
    FormFieldValidator<T>? validator,
  }) : super(
          {
            'label': StateValue<String?>(label),
            'textStyle': StateValue<TextStyle?>(textStyle),
          }, //this is a initStateMap
          name:name,
          initialValue: initialValue,
          validator: validator,
          onChanged: onChanged,
          builder: (state) {
            bool readOnly = state.readOnly;
            Map<String, dynamic> stateMap = state.currentMap;
            ThemeData themeData = Theme.of(context);
            // state is ValueFieldState<T>,if you override ValueFieldState,you can cast it as your custom ValueFieldState,in this example you can cast it to _CustomNullableValueFieldState,you can get name via state.name(nullable)
            // readOnly : whether this field should readOnly
            // stateMap : can be regarded as the lastest initStateMap , user can change stateMap var FormFieldManagement's update,
            // in this example ,you should get label&textStyle form stateMap rather than directly use them
            return Row(
              children: [
                Text(
                  stateMap['label'] ??
                      'radio', //don't use just label here,you should get lastest label from stateMap,the key is initStateMap's label key
                  style: stateMap['textStye'],
                ),
                Radio<T>(
                  focusNode: state
                      .focusNode, //state has prepared a focusnode for you,just use it rather than create a new one
                  activeColor: themeData.primaryColor,
                  groupValue: state.value,
                  value: value,
                  onChanged:
                      readOnly ? null : (value) => state.didChange(value),
                )
              ],
            );
          },
        );

  @override
  _CustomNullableValueFieldState<T> createState() =>
      _CustomNullableValueFieldState();
}

if you also want to build custom ValueFieldState,extends it !

class _CustomNullableValueFieldState<T> extends BaseValueFieldState<T>
    with TextSelectionManagement // if you form field support textselection
{
  late final TextEditingController
      textEditingController; //just an example here !

  @override
  void initState() {
    super.initState();
    textEditingController = TextEditingController(
        text:
            widget.initialValue == null ? '' : widget.initialValue.toString());
  }

  @override
  void reset() {
    super.reset();
    textEditingController.text =
        widget.initialValue == null ? '' : widget.initialValue.toString();
  }

  @override
  void dispose() {
    textEditingController.dispose();
    super.dispose();
  }

  @override
  void selectAll() {
    setSelection(0, textEditingController.text.length);
  }

  @override
  void setSelection(int start, int end) {
    TextSelectionManagement.setSelectionWithTextEditingController(
        start, end, textEditingController);
  }
}

the last step is insert your field

FormBuilder.append(CustomNullableValueField<String>(
        onChanged: (value) => print(value), value: '123')),

build a nonnull value field is almost the same,just extends BaseNonnullValueField

this is an example:

class CustomNonnullableValueField extends BaseNonnullValueField<bool> {
  CustomNonnullableValueField({
    String? label,
    TextStyle? textStyle,
    required bool initialValue,
    ValueChanged<bool>? onChanged,
    NonnullFieldValidator<bool>? validator,
  }) : super(
          {
            'label': StateValue<String?>(label),
            'textStyle': StateValue<TextStyle?>(textStyle),
          },
          initialValue: initialValue,
          validator: validator,
          onChanged: onChanged,
          builder: (state) {
            bool readOnly = state.readOnly;
            Map<String, dynamic> stateMap = state.currentMap;
            ThemeData themeData = Theme.of(state.context);
            return Row(
              children: [
                Text(
                  stateMap['label'] ?? 'checkbox',
                  style: stateMap['textStye'],
                ),
                Checkbox(
                  activeColor: themeData.primaryColor,
                  value: state.value,
                  onChanged: readOnly ? null : (value) => state.didChange(value),
                )
              ],
            );
          },
        );
}

build a commonfield #


class Label extends BaseCommonField {
  final String label;
  Label(this.label, {int flex = 1})
      : super(
          {'label': StateValue<String>(label)},
          flex: flex,
          builder: (state) {
            Map<String, dynamic> stateMap = state.currentMap;
            ThemeData themeData = Theme.of(state.context);
            return Text(
              stateMap['label'],
              style: TextStyle(fontSize: 18, color: themeData.primaryColor),
            );
          },
        );
}

build a Stateless Field #

FormBuilder.append(Builder(builder: (context) {
          BuilderInfo info = BuilderInfo.of(context);
          Position position = info.position;
          return Expanded(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  'I\'m a stateless field',
                  style: TextStyle(fontSize: 20),
                ),
                Container(
                  color: info.themeData.primaryColor.withOpacity(0.3),
                  child: ListView(
                    shrinkWrap: true,
                    children: [
                      createRow('row', '${position.row}'),
                      createRow('column', '${position.column}'),
                      createRow('inline', '${info.inline}'),
                    ],
                  ),
                )
              ],
            ),
            flex: 1,
          );
        }))

project status #

1.0.0 release

1
likes
0
pub points
76%
popularity

Publisher

unverified uploader

flutter row-column based form builder, build form quickly,create field fast,less code,more powerful

Repository (GitHub)
View/report issues

License

unknown (LICENSE)

Dependencies

flutter

More

Packages that depend on form_builder