flutter Form 表單組件的初步解析

在一個正常的應用程序中, 表單是用戶交互的很重要的一部分

flutter 中你可以自己"綁定"用戶的輸入數據和 state 中的字段

當然, 還有另一個選擇, Flutter 內置了 Form 組件給我們使用, 這個組件是 flutter 框架提供出來幫助我們操作表單的一個組件, 應該是官方較爲推薦的方案

不過 Form 的相關中文文章不太多, 基本都是介紹一下 TextFormField 的使用, 更多的 api 雲裏霧裏的, 可能有些朋友不太好理解
我粗略的解析下源碼和自定義, 幫助看過的朋友理解下 Form 體系

Form 體系的簡單使用

自動校驗

官方提供給了我們一些組件來結合 Form 使用, 最常見的就是 TextFormField

import 'package:flutter/material.dart';

class SimpleUseComponent extends StatefulWidget {
  @override
  _SimpleUseComponentState createState() => _SimpleUseComponentState();
}

class _SimpleUseComponentState extends State<SimpleUseComponent> {
  @override
  Widget build(BuildContext context) {
    return Form(
      onChanged: () {
        print("form change");
      },
      child: Column(
        children: <Widget>[
          TextFormField(
            initialValue: "你好",
            validator: (value) {
              if (value.isEmpty) return "不能爲空";
              return null;
            },
            autovalidate: true,
          ),
        ],
      ),
    );
  }
}

當我輸入/刪除時, 會出現日誌: ‘form change’

20190722153013.png
有一個autovalidate的屬性, 這個屬性可以在TextFormField設置,也可以在Form設置, 自動提交驗證的意思, 默認是 false.
當我將所有字符都刪除時, 會出現’不能爲空’的提示. 這個是由 validator 實現的, 因爲我設置了autovalidatetrue, 然後這個返回值如果是 null, 則說明驗證通過, 不通過則返回不通過的字符串.

點擊後校驗

當然,有些表單不要求自動校驗, 可能是點擊某個按鈕後來校驗, 這種情況下, 就需要使用 Form.of 來獲取到表單狀態

話不多說, 代碼在下面:


class SimpleUseClickComponent extends StatefulWidget {
  @override
  _SimpleUseClickComponentState createState() =>
      _SimpleUseClickComponentState();
}

class _SimpleUseClickComponentState extends State<SimpleUseClickComponent> {
  @override
  Widget build(BuildContext context) {
    return Form(
      onChanged: () {
        print("form change");
      },
      child: Column(
        children: <Widget>[
          TextFormField(
            validator: (value) {
              if (value.isEmpty) return "不能爲空";
              return null;
            },
          ),
          Builder( // 這個 Builder 是
            builder: (ctx) => RaisedButton(
              child: Text('check'),
              onPressed: () {
                final formState = Form.of(ctx);
                formState.validate(); // 驗證
                // formState.reset(); // 重置
                // formState.save(); // 保存
              },
            ),
          ),
        ],
      ),
    );
  }
}

validate 會觸發 FormStatevalidation 回調

reset 會觸發 FormFieldStatereset 回調, 默認實現是將輸入框設置爲初始值

save 會觸發 FormFieldStatesave 回調, 可以在裏面寫一些邏輯(比如保存信息到數據庫等等)

Form 體系源碼

架構查看

Form 組件是 widgets 包內的的一個 Widget, 不是 MaterialCupertino 包內的, 它沒有用戶界面, 更多的是邏輯層面的一個組件

20190722152219.png

20190722152305.png

Form 體系中有 5 個類, 3 個 typedef 組成

FormScope 是一個InheritedWidget, 一般帶of方法的組件都會對應一個這個東西, 是獲取 FormFormState 的容器類

FormState 就是 Form 對應的 state

FormFieldForm下的子組件的通用類, 每個實現/繼承了這個類的子類就可以被Form管理, 比如 TextFieldForm 就是這麼一個組件

20190722161208.png

FormFieldStateFormField 對應的狀態, 其中包含了一些狀態信息

源碼解析

通過回調等手段實現了內部的交互, 詳細看截圖

Form 解析

2019-07-22 at 17.02.png

FormState 解析

在這裏插入圖片描述

FormField 解析

在這裏插入圖片描述

FormFieldState 解析

在這裏插入圖片描述

自定義 Form 子組件

有的時候表單中並不只有文本輸入, 還會有 Checkbox 等組件, 我這裏舉兩個例子來自定義一個 Form 子組件

自定義 CheckboxFormField

import 'package:flutter/material.dart';

class CheckboxFormField extends FormField<bool> {
  CheckboxFormField({
    bool initValue,
  }) : super(
          builder: CheckboxFormField.buildWidget,
          initialValue: initValue,
        );

  static Widget buildWidget(FormFieldState<bool> field) {
    return Checkbox(
      onChanged: (bool value) {
        field.didChange(value);
      },
      value: field.value,
    );
  }
}

一個簡單的自定義 CheckboxFormField 就完成了

置入 Form

import 'package:flutter/material.dart';

import 'custom_field.dart';

class FormComponent extends StatefulWidget {
  @override
  _FormComponentState createState() => _FormComponentState();
}

class _FormComponentState extends State<FormComponent> {
  @override
  Widget build(BuildContext context) {
    return Form(
      onChanged: () {
        print("on change");
      },
      child: ListView(
        children: <Widget>[
          CheckboxFormField(),
        ],
      ),
    );
  }
}

當我點擊時, 就會回調 on change

自定義 SliderFormField

class SliderFormField extends FormField<double> {
  SliderFormField()
      : super(
          builder: SliderFormField.buildWidget,
          initialValue: 50,
        );

  static Widget buildWidget(FormFieldState<double> field) {
    return Slider(
      onChanged: (double value) {
        field.didChange(value);
      },
      value: field.value,
      min: 0,
      max: 100,
      divisions: 100,
    );
  }
}

置入 Form 中

import 'package:flutter/material.dart';

import 'custom_field.dart';

class FormComponent extends StatefulWidget {
  @override
  _FormComponentState createState() => _FormComponentState();
}

class _FormComponentState extends State<FormComponent> {
  GlobalKey<FormState> formKey = GlobalKey();

  @override
  Widget build(BuildContext context) {
    return Form(
      key: formKey,
      onChanged: () {
        print("on change");
      },
      child: ListView(
        children: <Widget>[
          CheckboxFormField(),
          SliderFormField(),
          RaisedButton(
            onPressed: () {
              formKey.currentState.reset();
            },
            child: Text("reset"),
          ),
        ],
      ),
    );
  }
}

加入了一個Key用於獲取FormState, 觸發reset方法

截圖:

在這裏插入圖片描述

後記

本篇解析了一下 Form 的使用和源碼, 幫助朋友們更好的理解使用

項目倉庫

以上

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章