Flutter 如何封裝文本輸入框組件
UI組件封裝的考慮要點(diǎn)
封裝一個(gè) UI 組件,通常需要考慮下面這三個(gè)點(diǎn):
- 接口如何定義:即組件接收什么輸入?yún)?shù)來控制組件的外觀和行為;
- 與業(yè)務(wù)分離:UI 組件應(yīng)當(dāng)只負(fù)責(zé)界面,而不負(fù)責(zé)業(yè)務(wù),具體的業(yè)務(wù)應(yīng)當(dāng)由業(yè)務(wù)層完成;
- 簡(jiǎn)單易用:因?yàn)槭?UI 組件,要盡可能地簡(jiǎn)單易用,方便使用者快速上手。
文本輸入框接口定義
首先先看一下我們上一篇使用文本框的代碼,這里實(shí)際上只是調(diào)用了一個(gè)函數(shù)返回新的組件,之所以要這么做是因?yàn)橛脩裘?、密碼使用了成員屬性,需要根據(jù)不同的成員屬性來設(shè)置不同的行為,主要有:
- 文本框裝飾不同:包括占位符、前置圖標(biāo),后置圖標(biāo)的行為綁定了成員屬性以及不同的 TextEditingCongtroller。
- onChanged 事件回調(diào)內(nèi)容不同。
- 鍵盤類型和是否隱藏輸入內(nèi)容不同。
- 對(duì)應(yīng)表單的字段不同。
Widget _getPasswordInput() {
return _getInputTextField(
TextInputType.text,
obscureText: true,
controller: _passwordController,
decoration: InputDecoration(
hintText: "輸入密碼",
icon: Icon(
Icons.lock_open,
size: 20.0,
),
suffixIcon: GestureDetector(
child: Offstage(
child: Icon(Icons.clear),
offstage: _password == '',
),
onTap: () {
this.setState(() {
_password = '';
_passwordController.clear();
});
},
),
border: InputBorder.none,
),
onChanged: (value) {
this.setState(() {
_password = value;
});
},
);
}
而實(shí)際造成差別的原因是成員屬性之間的差異不同,如果是繼續(xù)使用成員屬性這種方式,無法解決這個(gè)問題。這時(shí)候我們可以考慮把整個(gè)表單放入一個(gè) Map 中,Map里配置不同字段對(duì)應(yīng)的差異化屬性,然后就可以做到通用的接口了,我們可以定義封裝后的組件接口:
Widget _getInputTextFieldNew(
String formKey,
String value, {
TextInputType keyboardType = TextInputType.text,
FocusNode focusNode,
controller: TextEditingController,
onChanged: Function,
String hintText,
IconData prefixIcon,
onClear: Function,
bool obscureText = false,
height = 50.0,
margin = 10.0,
}) {
//......
}
新增的參數(shù)如下:
- formKey:表示文本框?qū)?yīng)的是表單Map的哪個(gè)鍵;
- value:當(dāng)前表單的值,用于控制是否顯示清除按鈕
- onClear:定義右側(cè)清除按鈕的行為響應(yīng)
- onChanged:輸入內(nèi)容變比回調(diào)
代碼實(shí)現(xiàn)
抽離后的代碼與業(yè)務(wù)頁面無關(guān),因此需要抽離代碼,在 lib 目錄下新增一個(gè) components 目錄,增加一個(gè) form_util.dart 文件,用于存放通用的表單組件。實(shí)現(xiàn)的代碼如下所示:
class FormUtil {
static Widget textField(
String formKey,
String value, {
TextInputType keyboardType = TextInputType.text,
FocusNode focusNode,
controller: TextEditingController,
onChanged: Function,
String hintText,
IconData prefixIcon,
onClear: Function,
bool obscureText = false,
height = 50.0,
margin = 10.0,
}) {
return Container(
height: height,
margin: EdgeInsets.all(margin),
child: Column(
children: [
TextField(
keyboardType: keyboardType,
focusNode: focusNode,
obscureText: obscureText,
controller: controller,
decoration: InputDecoration(
hintText: hintText,
icon: Icon(
prefixIcon,
size: 20.0,
),
border: InputBorder.none,
suffixIcon: GestureDetector(
child: Offstage(
child: Icon(Icons.clear),
offstage: value == null || value == '',
),
onTap: () {
onClear(formKey);
},
),
),
onChanged: (value) {
onChanged(formKey, value);
}),
Divider(
height: 1.0,
color: Colors.grey[400],
),
],
),
);
}
}
組件使用
首先是使用 Map 定義當(dāng)前頁面的表單內(nèi)容,以便控制不同表單字段的呈現(xiàn)形式。
Map<String, Map<String, Object>> _formData = {
'username': {
'value': '',
'controller': TextEditingController(),
'obsecure': false,
},
'password': {
'value': '',
'controller': TextEditingController(),
'obsecure': true,
},
};
其次是定義統(tǒng)一的文本框 onChanged 和 onClear 方法,對(duì)應(yīng)為 _handleTextFieldChanged和_handleClear。通過 formKey 回傳的字段,可以更新對(duì)應(yīng) _formData 的內(nèi)容。這里注意使用了 as用法用于將一個(gè) Object 轉(zhuǎn)換為TextEditingController。這種轉(zhuǎn)換如果 Object 對(duì)應(yīng)的類型是TextEditingController的話能夠成功轉(zhuǎn)換,也能正常執(zhí)行后面的 clear()方法。但是如果是 null,直接這時(shí)候執(zhí)行 clear()方法,會(huì)報(bào)空指針異常。因此在轉(zhuǎn)換結(jié)果后面加了個(gè)問號(hào),這個(gè)表示是如果是 null 后面的方法不會(huì)執(zhí)行,從而不會(huì)出現(xiàn)空指針異常。這是 Flutter 2.0引入的 null safety 特性。其實(shí)這個(gè)特效在 PHP 7,Swift 語言早就有應(yīng)用了。
_handleTextFieldChanged(String formKey, String value) {
this.setState(() {
_formData[formKey]['value'] = value;
});
}
_handleClear(String formKey) {
this.setState(() {
_formData[formKey]['value'] = '';
(_formData[formKey]['controller'] as TextEditingController)?.clear();
});
}
之后是在使用 textField 的地方使用 FormUtil.textField 方法直接使用封裝好的文本框:
//...
FormUtil.textField(
'username',
_formData['username']['value'],
controller: _formData['username']['controller'],
hintText: '請(qǐng)輸入手機(jī)號(hào)',
prefixIcon: Icons.mobile_friendly,
onChanged: _handleTextFieldChanged,
onClear: _handleClear,
),
FormUtil.textField(
'password',
_formData['password']['value'],
controller: _formData['password']['controller'],
obscureText: true,
hintText: '請(qǐng)輸入密碼',
prefixIcon: Icons.lock_open,
onChanged: _handleTextFieldChanged,
onClear: _handleClear,
),
//...
可以看到,username和 password 兩個(gè)表單字段復(fù)用了_handleTextFieldChanged和_handleClear。整個(gè)代碼長度也減少了近50%,而且封裝的 FormUtil.textField 文本框也可以用于其他表單頁面,整個(gè)代碼的維護(hù)性和復(fù)用性都相比前一篇的有了很大的提高。
踩坑記錄
在封裝 文本框的時(shí)候,直接將 onClear 函數(shù)復(fù)制給了GesureDetector 的 onTap 屬性,結(jié)果每次輸入都會(huì)觸發(fā) onClear自動(dòng)清空文本框內(nèi)容。后來發(fā)現(xiàn)實(shí)際應(yīng)該是傳一個(gè)回調(diào)函數(shù),下面列出了兩種方式的不同:
//...
//錯(cuò)誤的方式
onTap:onClear,
//...
//...
//正確的方式
onTap:() {
onClear(formKey);
},
//...
總結(jié)
封裝UI 組件在實(shí)際開發(fā)過程中非常常見,一般來說當(dāng)我們看到設(shè)計(jì)稿的時(shí)候,首先是將設(shè)計(jì)稿拆分成多個(gè)組件,然后考慮一下其中的一些組件是不是在其他場(chǎng)合也會(huì)用到。如果有可能用到,就可以考慮封裝。封裝的時(shí)候先考慮對(duì)外接口參數(shù),然后注意UI 組件不應(yīng)該涉及到業(yè)務(wù),再就是盡可能地簡(jiǎn)便(比如有一些默認(rèn)值,減少必傳參數(shù))。當(dāng)然,如果公司在一開始就能夠由產(chǎn)品、設(shè)計(jì)和開發(fā)一起定一套組件,提前封裝將會(huì)使得后面的開發(fā)效率更高,但這取決于項(xiàng)目時(shí)間的緊急程度,時(shí)間充裕的話可以這么考慮。
以上就是Flutter 如何封裝文本輸入框的詳細(xì)內(nèi)容,更多關(guān)于Flutter 封裝文本輸入框的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
淺談Android中關(guān)于靜態(tài)變量(static)的使用問題
本文主要介紹了Android中關(guān)于靜態(tài)變量(static)的使用問題,具有一定的參考作用,下面跟著小編一起來看下吧2017-01-01
Android自定義View軟鍵盤實(shí)現(xiàn)搜索
本文給大家分享android自定義view軟鍵盤實(shí)現(xiàn)搜索,對(duì)android軟鍵盤相關(guān)知識(shí)感興趣的朋友一起學(xué)習(xí)吧2015-12-12
圖解Windows環(huán)境下Android Studio安裝和使用教程
這篇文章主要介紹了圖解Windows環(huán)境下Android Studio安裝和使用教程的相關(guān)資料,需要的朋友可以參考下2015-12-12
協(xié)程作用域概念迭代RxTask?實(shí)現(xiàn)自主控制
這篇文章主要為大家介紹了協(xié)程作用域概念迭代RxTask實(shí)現(xiàn)自主控制詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10
Android 開發(fā) 使用WebUploader解決安卓微信瀏覽器上傳圖片中遇到的bug
這篇文章主要介紹了Android 開發(fā) 使用WebUploader解決安卓微信瀏覽器上傳圖片中遇到的bug問題,本文給介紹的非常詳細(xì),需要的朋友可以參考下2016-11-11
Android筆記之:onConfigurationChanged詳解
本篇是對(duì)Android中onConfigurationChanged的使用進(jìn)行了詳細(xì)的分析介紹。需要的朋友參考下2013-05-05
Android微信搶紅包功能的實(shí)現(xiàn)原理淺析
快到新年了,微信紅包越來越多,那么基于程序是怎么實(shí)現(xiàn)的呢?今天小編給大家分享Android微信搶紅包功能的實(shí)現(xiàn)原理淺析,一起看看吧2017-01-01
Android編程之退出整個(gè)應(yīng)用程序的方法
這篇文章主要介紹了Android編程之退出整個(gè)應(yīng)用程序的方法,實(shí)例分析了Android直接關(guān)閉所有的Acitivity并退出應(yīng)用程序的實(shí)現(xiàn)技巧,需要的朋友可以參考下2015-12-12

