Flutter之基礎Widget之TextField

Flutter

TextField

TextField用於文本輸入,它提供了不少屬性,咱們先簡單介紹一下主要屬性的做用html

const TextField({
    Key key,
    // 編輯框的控制器,跟文本框的交互通常都經過該屬性完成,若是不建立的話默認會自動建立
    this.controller,
    // 用於控制`TextField`是否佔有當前鍵盤的輸入焦點, 使咱們和鍵盤交互的`handle`
    this.focusNode,
    
    // 用於控制`TextField`的外觀顯示,如提示文本、背景顏色、邊框等
    this.decoration = const InputDecoration(),
    // 鍵盤類型
    TextInputType keyboardType,
    // 決定鍵盤右下角按鈕顯示的內容
    this.textInputAction,
    // 設置什麼狀況下使用大寫字母, 默認不使用大寫字母
    this.textCapitalization = TextCapitalization.none,
    
    // 正在編輯的文本樣式, `TextStyle`
    this.style,
    // 輸入框文本的對其方式
    this.textAlign = TextAlign.start,
    // 輸入框文本的其實位置
    this.textDirection,
    
    // 是否自動獲取焦點, 默認`false`
    this.autofocus = false,
    // 是否隱藏正在編輯的文本,如用於輸入密碼的場景等,文本內容會用「•」替換, 默認`false`
    this.obscureText = false,
    // 是否自動校驗, 默認`false`
    this.autocorrect = true,
    
    // 輸入框能輸入的最大行數
    this.maxLines = 1,
    // 輸入框能輸入的最多字符個數
    this.maxLength,
    // 達到最大長度(`maxLength`)時是否阻止輸入, 默認`true`: 不能繼續輸入, `false`能夠繼續輸入
    this.maxLengthEnforced = true,
    
    // 輸入文本發生變化時的回調
    this.onChanged,
    // 點擊鍵盤完成按鈕時觸發的回調,該回調沒有參數,(){}
    this.onEditingComplete,
    // 點擊鍵盤完成按鈕時觸發的回調,該回調有參數,參數即爲當前輸入框中的值。(String){}
    this.onSubmitted,
    
    // 對輸入文本的校驗
    this.inputFormatters,
    // 輸入框是否可用, `false`則輸入框會被禁用
    this.enabled,
    
    // 光標的寬度
    this.cursorWidth = 2.0,
    // 光標的圓角
    this.cursorRadius,
    // 光標的顏色
    this.cursorColor,
    
    // 鍵盤的外觀, Brightness.light和dark
    this.keyboardAppearance,
    // 當TextField滾動時, 設置文本字段在滾動後的位置與可滾動項的邊緣的距離
    this.scrollPadding = const EdgeInsets.all(20.0),
    // 長按輸入的文本, 設置是否顯示剪切,複製,粘貼按鈕, 默認是顯示的
    this.enableInteractiveSelection = true,
    // 點擊輸入框時的回調(){}
    this.onTap,
})
複製代碼

controller

  • 編輯框的控制器,經過它能夠設置/獲取編輯框的內容、選擇編輯內容、監聽編輯文本改變事件
  • 大多數狀況下咱們都須要顯式提供一個controller來與文本框交互
  • 若是沒有提供controller,則TextField內部會自動建立一個
  • 下面是一個TextField的取值和賦值的操做
class TextFieldWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return ControllerText();
  }
}

class ControllerText extends State<TextFieldWidget> {
  TextEditingController _textController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Container(
      width: 414.0,
      height: 600.0,
      color: Colors.white12,
      child: Column(
        children: <Widget>[
          TextField(
            controller: _textController,
            decoration: InputDecoration(icon: Icon(Icons.phone_iphone), hintText: 'hintText'),
          ),
          RaisedButton(
            child: Text('賦值'),
            onPressed: (){
              setState(() {
                  _textController.text = "https://www.titanjun.top";
              });
            },
          ),
          RaisedButton(
            child: Text('取值'),
            onPressed: (){
              setState(() {});
            },
          ),
          Text(_textController.text)
        ],
      ),
    );
  }
}
複製代碼

image

focusNode

用於控制TextField是否佔有當前鍵盤的輸入焦點, 使咱們和鍵盤交互的handlegit

FocusNode focusNode1 = new FocusNode();

TextField(
    autofocus: true, 
    focusNode: focusNode1,//關聯focusNode1
    decoration: InputDecoration(
        labelText: "input1"
    ),
),

RaisedButton(
    child: Text("隱藏鍵盤"),
    onPressed: () {
    // 當全部編輯框都失去焦點時鍵盤就會收起  
        focusNode1.unfocus();
    },
),
複製代碼

decoration

用於控制TextField的外觀顯示,如提示文本、背景顏色、邊框等, 下面是InputDecoration的構造方法github

const InputDecoration({
    // 接收Widget, 在輸入框左側顯示的圖片 
    this.icon,
    
    // String, 輸入框的描述, 當輸入框獲取焦點時默認會浮動到上方
    this.labelText,
    // TextStyle, 樣式
    this.labelStyle,

    // 輔助文本, 位於輸入框下方,若是errorText不爲空的話,則helperText不顯示
    this.helperText,
    this.helperStyle,
    
    /// 提示文本,位於輸入框內部
    this.hintText,
    this.hintStyle,
    
    // 錯誤信息提示文本
    this.errorText,
    this.errorStyle,
    // errorText顯示的最大行數
    this.errorMaxLines,
    // errorText不爲空,輸入框沒有焦點時要顯示的邊框
    this.errorBorder,
    
    // labelText是否浮動,默認爲true,修改成false則labelText在輸入框獲取焦點時不會浮動且不顯示
    this.hasFloatingPlaceholder = true,
    // 改變輸入框是否爲密集型,默認爲false,修改成true時,圖標及間距會變小
    this.isDense,
    // 內間距
    this.contentPadding,
    
    // 位於輸入框內部起左側置的圖標
    this.prefixIcon,
    // 預先填充在輸入框左側的Widget,跟prefixText同時只能出現一個
    this.prefix,
    //預填充在輸入框左側的文本, 不可修改刪除,例如手機號前面預先加上區號等
    this.prefixText,
    this.prefixStyle,
    
    // 位於輸入框內部右側位置的圖標
    this.suffixIcon,
    // 預先填充在輸入框右側的Widget,跟suffixText同時只能出現一個
    this.suffix,
    // 預填充在輸入框右側的文本, 不可修改刪除
    this.suffixText,
    this.suffixStyle,
    
    // 位於右下方顯示的文本,經常使用於顯示輸入的字符數量
    this.counterText,
    this.counterStyle,
    
    // 至關於輸入框的背景顏色
    this.fillColor,
    // 若是爲true,則輸入使用fillColor指定的顏色填充
    this.filled,
    
    // 輸入框有焦點時的邊框,若是errorText不爲空的話,該屬性無效
    this.focusedBorder,
    // errorText不爲空時,輸入框有焦點時的邊框
    this.focusedErrorBorder,
    // 輸入框禁用時顯示的邊框,若是errorText不爲空的話,該屬性無效
    this.disabledBorder,
    // 輸入框可用時顯示的邊框,若是errorText不爲空的話,該屬性無效
    this.enabledBorder,
    // 正常狀況下的邊框
    this.border,
    // 輸入框是否可用
    this.enabled = true,
    // counterText的語義標籤, 若是賦值將替換counterText, 可是我試了好像沒什麼效果
    this.semanticCounterText,
  })
複製代碼

image

keyboardType

用於設置該輸入框默認的鍵盤輸入類型,取值以下:api

keyboardType: TextInputType.number,
複製代碼
TextInputType 含義
text 文本輸入鍵盤
multiline 多行文本,需和maxLines配合使用(設爲null或大於1)
number 純數字鍵盤
phone 電話號碼輸入鍵盤會彈出數字鍵盤並顯示* #
datetime 日期輸入鍵盤, Android上會顯示: -
emailAddress 電子郵件地址,會顯示@ .
url 鏈接輸入鍵盤, 會顯示/ .

textInputAction

決定鍵盤右下角按鈕顯示的內容, TextInputAction枚舉值bash

textInputAction 樣式
none 不支持iOS
unspecified 顯示return
done 顯示Done
go 顯示Go
search 顯示Search
send 顯示Send
next 顯示Next
previous 不支持iOS
continueAction 顯示Continue
join 顯示Join
route 顯示Route
emergencyCall 顯示Emergency Call

newline服務器

textCapitalization

設置什麼狀態下使用大寫字母鍵盤TextCapitalization枚舉值微信

enum TextCapitalization {
  // 每一個單詞的第一個字母使用大寫字母
  words,
  // 默認爲每一個句子的第一個字母使用大寫鍵盤。
  sentences,
  // 每一個字符默認使用大寫鍵盤
  characters,
  /// 不使用大寫字母鍵盤
  none,
}
複製代碼

textAlign

輸入框內文本在水平方向的對齊方式markdown

// 默認值
this.textAlign = TextAlign.start

// 全部枚舉值
left: 左對齊
right: 右對齊
center: 居中
start: 起始位置, 和textDirection有關
end: 終點位置, 和textDirection有關
justify: 文本的拉伸行,以軟換行符結束,以填充容器的寬度
複製代碼

textDirection

決定文本是從右向左對其仍是從左向右對齊iphone

enum TextDirection {
  rtl,
  ltr,
}
複製代碼

inputFormatters

  • 用於限制輸入的內容,接收一個TextInputFormatter類型的集合
  • TextInputFormatter是一個抽象類, 官方給咱們提供了他的三個子類,分別是
    • WhitelistingTextInputFormatter: 白名單校驗,也就是隻容許輸入符合規則的字符
    • BlacklistingTextInputFormatter: 黑名單校驗,除了規定的字符其餘的均可以輸入
    • LengthLimitingTextInputFormatter: 長度限制,跟maxLength做用相似
  • 構造函數以下
// 白名單校驗
WhitelistingTextInputFormatter(this.whitelistedPattern)
// 黑名單校驗
BlacklistingTextInputFormatter(
    this.blacklistedPattern, {
    // 當輸入禁止輸入的字符時候, 會被替換成設置的replacementString字符
    this.replacementString = '',
})
// 長度校驗
LengthLimitingTextInputFormatter(this.maxLength)

// whitelistedPattern和blacklistedPattern都是Pattern類型的,
abstract class RegExp implements Pattern {
    external factory RegExp(String source,
      {bool multiLine: false, bool caseSensitive: true});
}
複製代碼

使用介紹ide

// 白名單
inputFormatters: [
    // 只能輸入數字
    WhitelistingTextInputFormatter.digitsOnly,
    // 是能輸入小寫字母
    WhitelistingTextInputFormatter(RegExp("[a-z]"))
],

// 黑名單
inputFormatters: [
    // 不能輸入回車符
    BlacklistingTextInputFormatter.singleLineFormatter,
    // 不能輸入小寫字母
    BlacklistingTextInputFormatter(RegExp("[a-z]"), replacementString: '-')
],

// 字符限制
[LengthLimitingTextInputFormatter(10)]

// 也但是三種或兩種一塊兒使用一塊兒使用
inputFormatters: [
  // 不能輸入小寫字母
  BlacklistingTextInputFormatter(RegExp("[a-z]")),
  // 限制輸入10個字符
  LengthLimitingTextInputFormatter(10)
],
複製代碼

光標設置

設置輸入框光標的樣式

// 光標的寬度
this.cursorWidth = 2.0,
// 光標的圓角
this.cursorRadius,
// 光標的顏色
this.cursorColor,

// 示例以下
cursorWidth: 10,
cursorColor: Colors.cyan,
cursorRadius: Radius.circular(5),
複製代碼

enableInteractiveSelection

長按輸入的文本, 設置是否顯示剪切,複製,粘貼按鈕, 默認是顯示的

// 默認值
this.enableInteractiveSelection = true,
複製代碼

image

事件監聽

// 輸入文本發生變化時的回調,參數即爲輸入框中的值
onChanged: (val) {
    print(val);
},

// 點擊鍵盤的動做按鈕時的回調,沒有參數
onEditingComplete: (){
    print("點擊了鍵盤上的動做按鈕");
},

// 點擊鍵盤的動做按鈕時的回調,參數爲當前輸入框中的值
onSubmitted: (val){
    print("點擊了鍵盤上的動做按鈕,當前輸入框的值爲:${val}");
},

// 點擊輸入框時的回調(){}, 沒有參數
onTap: (){
    print('點擊輸入框');
},
複製代碼

Form

  • 實際業務中,在正式向服務器提交數據前,都會對各個輸入框數據進行合法性校驗,可是對每個TextField都分別進行校驗將會是一件很麻煩的事
  • Flutter提供了一個表單Form,它能夠對輸入框進行分組,而後進行一些統一操做,如輸入內容校驗、輸入框重置以及輸入內容保存。
  • Form繼承自StatefulWidget對象,它對應的狀態類爲FormState
// Form類的定義
const Form({
    Key key,
    @required this.child,
    
    // 是否自動校驗輸入內容;當爲true時,每個子FormField內容發生變化時都會自動校驗合法性,並直接顯示錯誤信息。不然,須要經過調用FormState.validate()來手動校驗
    this.autovalidate = false,
    
    // 決定Form所在的路由是否能夠直接返回(如點擊返回按鈕),該回調返回一個Future對象,若是Future的最終結果是false,則當前路由不會返回;若是爲true,則會返回到上一個路由。此屬性一般用於攔截返回按鈕
    this.onWillPop,
    
    // Form的任意一個子FormField內容發生變化時會觸發此回調
    this.onChanged,
})
複製代碼

FormField

Form的子元素必須是FormField類型,FormField是一個抽象類,FormState內部經過定義的屬性來完成操做,FormField部分定義以下:

const FormField({
    Key key,
    @required this.builder,
    // 保存回調
    this.onSaved,
    // 驗證回調
    this.validator,
    // 初始值
    this.initialValue,
    // 是否自動校驗。
    this.autovalidate = false,
    this.enabled = true,
})
複製代碼

TextFormField

爲了方便使用,Flutter提供了一個TextFormField,它繼承自FormField類,也是TextField的一個包裝類,因此除了FormField定義的屬性以外,它還包括TextField的屬性。

class TextFormField extends FormField<String> {
  
  TextFormField({
    Key key,
    this.controller,
    String initialValue,
    FocusNode focusNode,
    InputDecoration decoration = const InputDecoration(),
    TextInputType keyboardType,
    TextCapitalization textCapitalization = TextCapitalization.none,
    TextInputAction textInputAction,
    TextStyle style,
    TextDirection textDirection,
    TextAlign textAlign = TextAlign.start,
    bool autofocus = false,
    bool obscureText = false,
    bool autocorrect = true,
    bool autovalidate = false,
    bool maxLengthEnforced = true,
    int maxLines = 1,
    int maxLength,
    VoidCallback onEditingComplete,
    ValueChanged<String> onFieldSubmitted,
    FormFieldSetter<String> onSaved,
    FormFieldValidator<String> validator,
    List<TextInputFormatter> inputFormatters,
    bool enabled = true,
    Brightness keyboardAppearance,
    EdgeInsets scrollPadding = const EdgeInsets.all(20.0),
    bool enableInteractiveSelection = true,
  })
}
複製代碼

FormState

  • FormStateFormState類,能夠經過Form.of()GlobalKey得到。
  • 咱們能夠經過它來對Form的子元素FormField進行統一操做
  • 咱們看看其經常使用的三個方法:
// 調用此方法後,會調用Form子元素FormField的save回調,用於保存表單內容
  void save() {
    for (FormFieldState<dynamic> field in _fields)
      field.save();
  }

  /// 調用此方法後,會將子元素FormField的內容清空。
  void reset() {
    for (FormFieldState<dynamic> field in _fields)
      field.reset();
    _fieldDidChange();
  }

  /// 調用此方法後,會調用Form子元素FormField的validate回調,若是有一個校驗失敗,則返回false,全部校驗失敗項都會返回用戶返回的錯誤提示。
  bool validate() {
    _forceRebuild();
    return _validate();
  }
複製代碼

需求示例

用戶登陸示例, 在提交以前校驗:

  • 用戶名不能爲空,若是爲空則提示「用戶名不能爲空」。
  • 密碼不能小於6位,若是小於6爲則提示「密碼不能少於6位」。
class TextStateWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return TextWidget();
  }
}

class TextWidget extends State<TextStateWidget> {
  TextEditingController _nameController = TextEditingController();
  TextEditingController _psdController = TextEditingController();
  GlobalKey _formKey = GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: EdgeInsets.symmetric(vertical: 20, horizontal: 30),
      child: Form(
        key: _formKey,
        autovalidate: true,
        child: Column(
          children: <Widget>[
            TextFormField(
              autofocus: true,
              controller: _nameController,
              decoration: InputDecoration(
                labelText: '用戶名',
                hintText: '用戶名或密碼',
                icon: Icon(Icons.person)
              ),
              validator: (value) {// 校驗用戶名
                return value.trim().length > 0 ? null : '用戶名不能爲空';
              },
            ),
            TextFormField(
              controller: _psdController,
              obscureText: true,
              decoration: InputDecoration(
                labelText: '密碼',
                hintText: '登陸密碼',
                icon: Icon(Icons.lock)
              ),
              validator: (psd) {
                return psd.trim().length > 5 ? null : '密碼不能少於6位';
              },
            ),
            Padding(
              padding: EdgeInsets.only(top: 30),
              child: Row(
                children: <Widget>[
                  Expanded(
                    child: RaisedButton(
                      padding: EdgeInsets.all(15),
                      child: Text('登陸'),
                      color: Theme.of(context).primaryColor,
                      textColor: Colors.white,
                      onPressed: () {
                        // 反正這裏我是沒看懂, 後面再慢慢學習吧
                        if((_formKey.currentState as FormState).validate()){
                          //驗證經過提交數據
                        }
                      },
                    ),
                  )
                ],
              ),
            )
          ],
        ),
      ),
    );
  }
}
複製代碼

image

好了, 到這裏TextField相關的知識已經介紹完了, 下一篇應該就是介紹容器類Widget了, 拭目以待吧

參考文獻


歡迎您掃一掃下面的微信公衆號,訂閱個人博客!

微信公衆號
相關文章
相關標籤/搜索