Dart & Flutter 開發技巧 8-14
972
2025-04-01
小菜剛學習了 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:
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:
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 會有或多或少的更新,如有問題請多多指導!
來源: 阿策小和尚
Flutter
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。