“這是我參與8月更文挑戰的第23天,活動詳情檢視: 8月更文挑戰” juejin.cn/post/698796…
小菜剛學習了 TextField 的基本用法,今天特意學習一下 TextField InputDecoration 文字框裝飾器的相關內容;
InputDecoration 原始碼分析
const InputDecoration({
this.icon, // 裝飾器外小圖示
this.labelText, // 文字框描述標籤
this.labelStyle, // 文字框描述標籤樣式
this.helperText, // 文字框輔助標籤
this.helperStyle, // 文字框輔助標籤樣式
this.hintText, // 文字框預設提示資訊
this.hintStyle, // 文字框預設提示資訊樣式
this.hintMaxLines, // 文字框預設提示資訊最大行數
this.errorText, // 文字框錯誤提示資訊
this.errorStyle, // 文字框錯誤提示資訊樣式
this.errorMaxLines, // 文字框錯誤提示資訊最大行數
this.hasFloatingPlaceholder = true, // 文字框獲取焦點後 labelText 是否向上浮動
this.isDense, // 是否問緊湊型文字框
this.contentPadding, // 文字內邊距
this.prefixIcon, // 前置圖示
this.prefix, // 前置預填充 Widget
this.prefixText, // 前置預填充文字
this.prefixStyle, // 前置預填充樣式
this.suffixIcon, // 後置圖示
this.suffix, // 後置預填充 Widget
this.suffixText, // 後置預填充文字
this.suffixStyle, // 後置預填充樣式
this.counter, // 輸入框右下角 Widget
this.counterText, // 輸入框右下角文字
this.counterStyle, // 輸入框右下角樣式
this.filled, // 是否顏色填充文字框
this.fillColor, // 填充顏色
this.errorBorder, // errorText 存在時未獲取焦點邊框
this.focusedBorder, // 獲取焦點時邊框
this.focusedErrorBorder, // errorText 存在時獲取焦點邊框
this.disabledBorder, // 不可用時邊框
this.enabledBorder, // 可用時邊框
this.border, // 邊框
this.enabled = true, // 輸入框是否可用
this.semanticCounterText,
this.alignLabelWithHint, // 覆蓋將標籤與 TextField 的中心對齊
})
const InputDecoration.collapsed({
@required this.hintText,
this.hasFloatingPlaceholder = true,
this.hintStyle,
this.filled = false,
this.fillColor,
this.border = InputBorder.none,
this.enabled = true,
})
複製程式碼
分析原始碼可知,Flutter 不僅提供了全面的構建裝飾器的方式,還提供了簡單便利的構建方式 collapsed 預設是無邊框的,且無法設定標籤等其他屬性;
案例嘗試
- icon 為裝飾器外小圖示,可靈活設定圖示或其他 Widget,預設距輸入框 16dp,主題可通過 IconTheme 設定;
return TextField(decoration: InputDecoration(icon: Image.asset('images/ic_launcher.png')));
return TextField(decoration: InputDecoration(icon: Icon(Icons.android)));
複製程式碼
- labelText 為文字框描述標籤,為 String 型別,直接編輯內容即可;labelStyle 為標籤樣式屬性;TextField 獲取焦點之後描述標籤上移;
return TextField(decoration: InputDecoration(
labelText: '使用者名稱:', labelStyle: TextStyle(color: Colors.purple)));
複製程式碼
- helperText 為文字框輔助標籤,一般在文字框底部,提示性內容;helperStyle 為文字框輔助標籤樣式屬性;與 TextField 是否獲取焦點無變化;
return TextField(decoration: InputDecoration(
labelText: '使用者名稱:', labelStyle: TextStyle(color: Colors.purple),
helperText: '請輸入手機號或郵箱!', helperStyle: TextStyle(color: Colors.teal)));
複製程式碼
- hintText 為文字框預設提示資訊,若設定 labelText,則 TextField 在未獲取焦點時優先展示 labelText;hintStyle 為文字框提示資訊樣式屬性;hintMaxLines 為提示資訊過長時允許展示的最大行數;
return TextField(decoration: InputDecoration(
hintStyle: TextStyle(color: Colors.brown), hintMaxLines: 1, hintText: '請輸入使用者名稱資訊!請輸入使用者名稱資訊!請輸入使用者名稱資訊!請輸入使用者名稱資訊!請輸入使用者名稱資訊!請輸入使用者名稱資訊!請輸入使用者名稱資訊!請輸入使用者名稱資訊!請輸入使用者名稱資訊!請輸入使用者名稱資訊!請輸入使用者名稱資訊!'));
return TextField(decoration: InputDecoration(
labelText: '使用者名稱:', labelStyle: TextStyle(color: Colors.purple),
helperText: '請輸入手機號或郵箱!', helperStyle: TextStyle(color: Colors.teal),
hintText: '請輸入使用者名稱資訊!請輸入使用者名稱資訊!請輸入使用者名稱資訊!請輸入使用者名稱資訊!請輸入使用者名稱資訊!請輸入使用者名稱資訊!請輸入使用者名稱資訊!請輸入使用者名稱資訊!請輸入使用者名稱資訊!請輸入使用者名稱資訊!請輸入使用者名稱資訊!',
hintStyle: TextStyle(color: Colors.brown), hintMaxLines: 2));
複製程式碼
- errorText 為文字框錯誤提示資訊,一般在文字框底部,當設定 errorText 時不展示 helperText,整體預設為紅色;errorStyle 為錯誤提示資訊樣式屬性;errorMaxLines 為錯誤資訊過長時允許展示的最大行數;與 hintText 類似;
return TextField(onChanged: (text) { setState(() { _textLength = text.length; }); },
decoration: InputDecoration(
labelText: '使用者名稱:', labelStyle: TextStyle(color: Colors.purple),
helperText: '請輸入手機號或郵箱!', helperStyle: TextStyle(color: Colors.teal),
hintText: '請輸入使用者名稱資訊!', hintStyle: TextStyle(color: Colors.brown),
errorText: _textLength > 11 ? '請勿超過 11 位使用者名稱!' : null, errorStyle: TextStyle(color: Colors.pink)));
複製程式碼
- hasFloatingPlaceholder 設定 TextField 獲取焦點時 labelText 是否向上浮動;設定為 false 時,獲取焦點後 labelText 隱藏,不會向上浮動;
return TextField(decoration: InputDecoration(labelText: '使用者名稱:', labelStyle: TextStyle(color: Colors.purple),
hasFloatingPlaceholder: false));
複製程式碼
- isDense 是否為緊湊型文字框,true 為緊湊型文字框,圖示等與輸入框邊距較小;
return TextField(decoration: InputDecoration(icon: Icon(Icons.android), isDense: false));
return TextField(decoration: InputDecoration(icon: Icon(Icons.android), isDense: true));
複製程式碼
- contentPadding 為編輯內容與文字框內邊距;
returnTextField(decoration: InputDecoration(contentPadding: EdgeInsets.all(20.0)));
複製程式碼
- prefix... 是文字框前置元件,prefixIcon 為前置圖示,固定在文字輸入框前邊,與 icon 位置不同,其樣式通過 IconTheme 調整;prefixText 為前置預填充文字,例如手機號前(+86) 之類;prefix 為前置預填充元件,可自由設定,更為靈活,但不能與 prefixText 同時使用;prefixStyle 為預填充元件樣式;
return TextField(decoration: InputDecoration(
prefixIcon: Icon(Icons.supervised_user_circle), prefixText: '(+86)', prefixStyle: TextStyle(color: Colors.purple.withOpacity(0.4))));
return TextField(decoration: InputDecoration(
prefixIcon: Icon(Icons.supervised_user_circle), prefixStyle: TextStyle(color: Colors.purple.withOpacity(0.4)),
prefix: Row(mainAxisSize: MainAxisSize.min, children: <Widget>[Icon(Icons.phone), Text('(+86)')])));
複製程式碼
- suffix... 為文字框後置元件系列;與 prefix... 用法一致;
return TextField(decoration: InputDecoration(
suffixIcon: Icon(Icons.close), suffixText: '關閉', suffixStyle: TextStyle(color: Colors.purple.withOpacity(0.4))));
return TextField(decoration: InputDecoration(
suffixIcon: Icon(Icons.close), suffixStyle: TextStyle(color: Colors.purple.withOpacity(0.4)),
suffix: Row(mainAxisSize: MainAxisSize.min, children: <Widget>[Text('關閉'), Icon(Icons.remove_red_eye)])));
複製程式碼
- counter 系列為文字框右下角計數器,當設定 maxLengths 時通常會在右下角展示編輯字元數與整體數量比,可通過 counter 系列元件調整;counterText 為計數器展示內容;counterStyle 為計數器樣式屬性;
return TextField(maxLength: 20,
decoration: InputDecoration(counterText: '最大長度不超過20', counterStyle: TextStyle(color: Colors.blueAccent)));
複製程式碼
- filled 為文字框是否顏色填充,只有 true 時,filledColor 才生效;
return TextField(decoration: InputDecoration(fillColor: Colors.green.withOpacity(0.4), filled: true));
複製程式碼
- enabled 為文字框是否可用,false 為不可用,無法獲取焦點;
return TextField(decoration: InputDecoration(enabled: false));
複製程式碼
- alignLabelWithHint 用於 TextField 設定多行時,true 時覆蓋將標籤與 TextField 的中心對齊的預設行為,小菜嘗試了多種情況下 true 和 false 狀態,發現效果並不明顯,有待繼續研究;
return TextField(maxLines: null, decoration: InputDecoration(
alignLabelWithHint: true, labelText: '使用者名稱:',
hintMaxLines: null, helperText: '請輸入手機號或郵箱!',
hintText: '請輸入使用者名稱資訊!請輸入使用者名稱資訊!請輸入使用者名稱資訊!請輸入使用者名稱資訊!請輸入使用者名稱資訊!請輸入使用者名稱資訊!',
));
複製程式碼
- border 為一個系列,包括各種環境下邊框;預設 border 為正常狀態下邊框;邊框基本包括三類:
a. InputBorder 一般設定為無邊框樣式;
return TextField(decoration: InputDecoration(border: InputBorder.none));
複製程式碼
b. UnderlineInputBorder 一般設定為底部一條直線邊框樣式;小菜測試時設定邊框圓角為 10dp 加上背景色效果更明顯;
return TextField(decoration: InputDecoration(
filled: true, fillColor: Colors.green.withOpacity(0.4),
border: UnderlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(10.0)),
borderSide: BorderSide(color: Colors.purple, width: 4.0, style: BorderStyle.solid))));
複製程式碼
c. OutlineInputBorder 一般設定為包圍的圓角邊框;相較於 UnderlineInputBorder 多了 gapPadding 屬性,用於浮動的 labelText 與邊框的間距;
return TextField(decoration: InputDecoration(
labelText: '使用者名稱:', labelStyle: TextStyle(color: Colors.purple),
border: OutlineInputBorder(
gapPadding: 10.0, borderRadius: BorderRadius.all(Radius.circular(10.0)),
borderSide: BorderSide(color: Colors.purple, width: 4.0, style: BorderStyle.solid))));
複製程式碼
小菜測試發現 UnderlineInputBorder 和 OutlineInputBorder 對於設定 border 邊框顏色無效,需要通過 ThemeData 來更改屬性;
- enabledBorder 為可用時邊框樣式,enabled 為 true;
Tips:
- errorText 存在時 enabledBorder 不生效;
- 若不設定其他 border 屬性,獲取焦點預設是 ThemeData 中焦點邊框,設定 border 或 focusedBorder 等生效;
// UnderlineInputBorder 型別且只設定 enabledBorder
return TextField(decoration: InputDecoration(filled: true,fillColor: Colors.green.withOpacity(0.4),
enabledBorder: UnderlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(10.0)), borderSide: BorderSide(color: Colors.purple, width: 4.0))));
// UnderlineInputBorder 型別且設定 enabledBorder 和 border
return TextField(decoration: InputDecoration(filled: true, fillColor: Colors.green.withOpacity(0.4),
enabledBorder: UnderlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(10.0)), borderSide: BorderSide(color: Colors.purple, width: 4.0)),
border: UnderlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(10.0)))));
// UnderlineInputBorder 型別且 errorText 不為空
return TextField(decoration: InputDecoration(filled: true, fillColor: Colors.green.withOpacity(0.4),
errorText: '請勿超過 11 位!', errorStyle: TextStyle(color: Colors.pink),
enabledBorder: UnderlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(10.0)), borderSide: BorderSide(color: Colors.purple, width: 4.0)),
border: UnderlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(10.0)))));
// OutlineInputBorder 型別且只設定 enabledBorder
return TextField(decoration: InputDecoration(labelText: '使用者名稱:', labelStyle: TextStyle(color: Colors.purple),
enabledBorder: OutlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(10.0)), borderSide: BorderSide(color: Colors.purple.withOpacity(0.4), width: 3.0)),
border: OutlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(10.0)))));
// OutlineInputBorder 型別設定 enabledBorder,且 errorText 不為空
return TextField(decoration: InputDecoration(labelText: '使用者名稱:', labelStyle: TextStyle(color: Colors.purple),
errorText: '請勿超過 11 位!', errorStyle: TextStyle(color: Colors.pink),
enabledBorder: OutlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(10.0)), borderSide: BorderSide(color: Colors.purple.withOpacity(0.4), width: 3.0))));
// OutlineInputBorder 類,設定 enabledBorder 和 border 且 errorText 不為空
return TextField(decoration: InputDecoration(labelText: '使用者名稱:', labelStyle: TextStyle(color: Colors.purple),
errorText: '請勿超過 11 位!', errorStyle: TextStyle(color: Colors.pink),
enabledBorder: OutlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(10.0)), borderSide: BorderSide(color: Colors.purple.withOpacity(0.4), width: 3.0)),
border: OutlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(10.0)))));
複製程式碼
- disabledBorder 為不可用時邊框,enabled 為 false;且 errorText 存在時 disabledBorder 不生效;
// UnderlineInputBorder 型別
return TextField( decoration: InputDecoration(enabled: false,
filled: true, fillColor: Colors.green.withOpacity(0.4),
disabledBorder: UnderlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(10.0)), borderSide: BorderSide(color: Colors.pink, width: 4.0))));
// UnderlineInputBorder 型別且設定 errorText
return TextField(decoration: InputDecoration(enabled: false,
filled: true, fillColor: Colors.green.withOpacity(0.4),
errorText: '請勿超過 11 位!', errorStyle: TextStyle(color: Colors.pink),
disabledBorder: UnderlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(10.0)), borderSide: BorderSide(color: Colors.pink, width: 4.0)));
// OutlineInputBorder 型別
return TextField(decoration: InputDecoration(enabled: false,
labelText: '使用者名稱:', labelStyle: TextStyle(color: Colors.purple),
disabledBorder: OutlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(10.0)), borderSide: BorderSide(color: Colors.green, width: 4.0))));
// OutlineInputBorder 型別且設定 errorText
return TextField(decoration: InputDecoration(enabled: false,
labelText: '使用者名稱:', labelStyle: TextStyle(color: Colors.purple),
errorText: '請勿超過 11 位!', errorStyle: TextStyle(color: Colors.pink),
disabledBorder: OutlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(10.0)), borderSide: BorderSide(color: Colors.pink, width: 4.0))));
複製程式碼
- focusedBorder 為獲取焦點時邊框,errorText 存在時 focusedBorder 不生效;
// UnderlineInputBorder 型別
return TextField(decoration: InputDecoration(
filled: true, fillColor: Colors.green.withOpacity(0.4),
focusedBorder: UnderlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(10.0)), borderSide: BorderSide(color: Colors.pink, width: 4.0)),
enabledBorder: UnderlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(10.0)), borderSide: BorderSide(color: Colors.purple, width: 4.0))));
// UnderlineInputBorder 型別且設定 errorText
return TextField(decoration: InputDecoration(
filled: true, fillColor: Colors.green.withOpacity(0.4),
errorText: '請勿超過 11 位!', errorStyle: TextStyle(color: Colors.pink),
focusedBorder: UnderlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(10.0)), borderSide: BorderSide(color: Colors.pink, width: 4.0)),
enabledBorder: UnderlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(10.0)), borderSide: BorderSide(color: Colors.purple, width: 4.0))));
// OutlineInputBorder 型別
return TextField(decoration: InputDecoration(
labelText: '使用者名稱:', labelStyle: TextStyle(color: Colors.purple),
enabledBorder: OutlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(10.0)), borderSide: BorderSide(color: Colors.purple.withOpacity(0.4), width: 3.0)),
focusedBorder: OutlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(10.0)), borderSide: BorderSide(color: Colors.green, width: 4.0))));
// OutlineInputBorder 型別且設定 errorText
return TextField(decoration: InputDecoration(
labelText: '使用者名稱:', labelStyle: TextStyle(color: Colors.purple),
errorText: '請勿超過 11 位!', errorStyle: TextStyle(color: Colors.pink),
focusedBorder: OutlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(10.0)), borderSide: BorderSide(color: Colors.pink, width: 4.0)),
enabledBorder: OutlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(10.0)), borderSide: BorderSide(color: Colors.purple.withOpacity(0.4), width: 3.0))));
複製程式碼
- errorBorder 為 errorText 不為空且未獲取焦點時邊框;
// UnderlineInputBorder 型別
return TextField(decoration: InputDecoration(
filled: true, fillColor: Colors.green.withOpacity(0.4),
errorText: '請勿超過 11 位!', errorStyle: TextStyle(color: Colors.pink),
errorBorder: UnderlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(10.0)), borderSide: BorderSide(color: Colors.black.withOpacity(0.4), width: 4.0))));
// OutlineInputBorder 型別
return TextField(decoration: InputDecoration(
labelText: '使用者名稱:', labelStyle: TextStyle(color: Colors.purple),
errorText: '請勿超過 11 位!', errorStyle: TextStyle(color: Colors.pink),
errorBorder: OutlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(10.0)), borderSide: BorderSide(color: Colors.black.withOpacity(0.4), width: 3.0))));
複製程式碼
- focusedErrorBorder 為 errorText 不為空且獲取焦點時邊框;
// UnderlineInputBorder 型別
return TextField(decoration: InputDecoration(
filled: true, fillColor: Colors.green.withOpacity(0.4),
errorText: '請勿超過 11 位!', errorStyle: TextStyle(color: Colors.pink),
focusedErrorBorder: UnderlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(10.0)), borderSide: BorderSide(color: Colors.teal, width: 4.0)),
errorBorder: UnderlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(10.0)), borderSide: BorderSide(color: Colors.black, width: 4.0))));
// OutlineInputBorder 型別
return TextField(decoration: InputDecoration(
labelText: '使用者名稱:', labelStyle: TextStyle(color: Colors.purple),
errorText: '請勿超過 11 位!', errorStyle: TextStyle(color: Colors.pink),
focusedErrorBorder: OutlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(10.0)), borderSide: BorderSide(color: Colors.pink, width: 4.0)),
errorBorder: OutlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(10.0)), borderSide: BorderSide(color: Colors.purple.withOpacity(0.4), width: 3.0))));
複製程式碼
小擴充套件
在實際開發中,可能回隨時需要關閉鍵盤,此時我們僅需監聽一下即可;小菜監聽一個文字輸入框,當輸入字元長度大於 11 位時即收起鍵盤;
return TextField(controller: controller,
decoration: InputDecoration(
labelText: '使用者名稱:', labelStyle: TextStyle(color: Colors.purple),
errorText: '請勿超過 11 位!', errorStyle: TextStyle(color: Colors.pink)));
void initState() {
super.initState();
controller.addListener(() {
setState(() {
if (controller.text.length >= 11) {
// 收起鍵盤
FocusScope.of(context).requestFocus(FocusNode());
}
});
});
}
複製程式碼
文字輸入框確實有很多細節需要研究和嘗試,小菜僅初步瞭解,有待深入研究;且小菜建議時常升級 Flutter 版本,可能對於同一個 Widget 會有或多或少的更新,如有問題請多多指導!
來源: 阿策小和尚