上一篇:Flutter解決有輸入框的頁(yè)面豪治,點(diǎn)擊非輸入框部分自動(dòng)關(guān)閉鍵盤及鍵盤相關(guān)筆記
前言
在上一篇里接受了如何添加點(diǎn)擊空白頁(yè)面關(guān)閉鍵盤及展示鍵盤的ToolBar,現(xiàn)在對(duì)這兩個(gè)功能封裝成一個(gè)工具罢浇,讓需要有這兩個(gè)功能的頁(yè)面幾行代碼就能集成相關(guān)功能
使用步驟:
Step1: 準(zhǔn)備工作
BlankToolBarModel blankToolBarModel = BlankToolBarModel();
void initState() {
// Step1.1: 焦點(diǎn)變化時(shí)的響應(yīng)
blankToolBarModel.outSideCallback = focusNodeChange;
super.initState();
}
// Step1.2: 焦點(diǎn)變化時(shí)的響應(yīng)操作
void focusNodeChange(){
setState(() {});
}
@override
void dispose() {
// Step1.3: 在銷毀頁(yè)面時(shí)取消監(jiān)聽(tīng)
blankToolBarModel.removeFocusListeners();
super.dispose();
}
Step2: 由tool提供FocusNode創(chuàng)建TextField
// 創(chuàng)建輸入行
Widget createInputText(TextEditingController controller){
// Step5.1 由controller獲得FocusNode
FocusNode focusNode = blankToolBarModel.getFocusNodeByController(controller);
// 輸入框
TextField textField = TextField(
controller: controller,
keyboardType: TextInputType.text,
focusNode: focusNode,
);
return textField;
}
Step3: 用tool創(chuàng)建body
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('登錄'),),
// Step4 用tool創(chuàng)建body
body: BlankToolBarTool.blankToolBarWidget(
context,
model:blankToolBarModel,
body:xxx這里真正創(chuàng)建的body展示內(nèi)容xxxx
),
);
}
完整例子:
import 'package:BlankToolBarTool.dart';
import 'package:flutter/material.dart';
class LoginPage5 extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return LoginPage5State();
}
}
class LoginPage5State extends State<LoginPage5>{
TextEditingController nameController = TextEditingController();
TextEditingController pwdController = TextEditingController();
TextEditingController codeController = TextEditingController();
// Step1: 響應(yīng)空白處的焦點(diǎn)的Node
BlankToolBarModel blankToolBarModel = BlankToolBarModel();
@override
void initState() {
// Step2.1: 焦點(diǎn)變化時(shí)的響應(yīng)
blankToolBarModel.outSideCallback = focusNodeChange;
super.initState();
}
// Step2.2: 焦點(diǎn)變化時(shí)的響應(yīng)操作
void focusNodeChange(){
setState(() {});
}
@override
void dispose() {
// Step3: 在銷毀頁(yè)面時(shí)取消監(jiān)聽(tīng)
blankToolBarModel.removeFocusListeners();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('登錄'),),
// Step4 用tool創(chuàng)建body
body: BlankToolBarTool.blankToolBarWidget(
context,
model:blankToolBarModel,
body:createBody()
),
);
}
Widget createBody(){
return ListView(
padding: EdgeInsets.only(left: 20,right: 20),
children: <Widget>[
SizedBox(height: 30),
createInputText(nameController,hint: '請(qǐng)輸入用戶名',icon: Icons.people),
SizedBox(height: 30),
createInputText(pwdController,hint: '請(qǐng)輸入密碼',icon: Icons.power,obscureText:true),
SizedBox(height: 30),
createInputText(codeController,hint: '請(qǐng)輸驗(yàn)證碼',icon: Icons.nature,obscureText:true),
SizedBox(height: 30),
FlatButton(color: Colors.blue,child: Text('登錄'),onPressed: checkLogin,)
],
);
}
// 創(chuàng)建輸入行
Widget createInputText(TextEditingController controller,{obscureText: false,String hint,IconData icon}){
// Step5.1 由controller獲得FocusNode
FocusNode focusNode = blankToolBarModel.getFocusNodeByController(controller);
// 輸入框
TextField textField = TextField(
controller: controller,
keyboardType: TextInputType.text,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(10.0),
hintText: hint,
),
obscureText: obscureText,
// Step5.2 設(shè)置FocusNode
focusNode: focusNode,
);
List<Widget> rowList = [];
// 輸入框前的提示圖標(biāo)
rowList.add(SizedBox(width: 10));
rowList.add(Icon(icon));
// 輸入框
rowList.add(Expanded(child: textField));
return Row(children: rowList);
}
// 點(diǎn)擊登錄處理
void checkLogin(){
print(nameController.text);
print(pwdController.text);
print(codeController.text);
}
}
工具類BlankToolBarTool.dart
import 'ToolBar.dart';
import 'package:flutter/material.dart';
/// 用于持有FocusNode的類
class BlankToolBarModel {
// 點(diǎn)擊空白部分用于響應(yīng)的FocusNode
FocusNode blankModel=FocusNode();
// 保存頁(yè)面中所有InputText綁定的FocusNode
Map<String,ToolBarModel> focusNodeMap={};
FocusNode _currentEditingNode;
// 用于外側(cè)的回調(diào)
VoidCallback outSideCallback;
BlankToolBarModel({this.outSideCallback});
/**
* 通過(guò)一個(gè)key獲取node,一般是通過(guò)TextEditingController對(duì)象的hashCode
* TextEditingController nickNameController = TextEditingController();
* String key = nickNameController.hashCode.toString();
* FocusNode focusNode = blankToolBarModel.getFocusNode(key);
*/
FocusNode getFocusNode(String key){
ToolBarModel barModel = focusNodeMap[key];
if(barModel == null){
barModel = ToolBarModel(index: focusNodeMap.length,focusNode: FocusNode());
barModel.focusNode.addListener(focusNodeListener);
focusNodeMap[key] = barModel;
}
return barModel.focusNode;
}
/**
* 通過(guò)controller獲取focusNode
*/
FocusNode getFocusNodeByController(TextEditingController controller){
String key = controller.hashCode.toString();
return getFocusNode(key);
}
/**
* 找到正處于編輯狀態(tài)的FocusNode
*/
FocusNode findEditingNode(){
for(ToolBarModel barModel in focusNodeMap.values){
if(barModel.focusNode.hasFocus){
return barModel.focusNode;
}
}
return null;
}
// 監(jiān)聽(tīng)FocusNode變化
Future<Null> focusNodeListener() async {
FocusNode editingNode = findEditingNode();
if(_currentEditingNode != editingNode){
_currentEditingNode = editingNode;
print('>>>>>>>>+++++++++++');
if(outSideCallback != null){
outSideCallback();
}
}else{
print('>>>>>>>>----------');
}
}
/// 移除所有監(jiān)聽(tīng)
void removeFocusListeners(){
for(ToolBarModel barModel in focusNodeMap.values){
barModel.focusNode.removeListener(focusNodeListener);
}
}
/// 關(guān)閉鍵盤
void closeKeyboard(BuildContext context){
FocusScope.of(context).requestFocus(blankModel);
}
}
/**
* 增加
* 1沐祷、自動(dòng)處理點(diǎn)擊空白頁(yè)面關(guān)閉鍵盤嚷闭,
* 2、鍵盤上方增加一個(gè)toolbar
*/
class BlankToolBarTool{
static Widget blankToolBarWidget(
// 上下文
BuildContext context,
{
// 數(shù)據(jù)model
BlankToolBarModel model,
// 要展示的子內(nèi)容
Widget body,
// 是否展示toolBar
bool showToolBar = true,
// 默認(rèn)的toolBar的高度
double toolBarHeight = 40,
// toolBar的背景色
Color toolBarColor = const Color(0xffeeeeee),
// toolBar的可點(diǎn)擊按鈕的顏色
Color toolBarTintColor = Colors.blue
}
){
if(!showToolBar){
return GestureDetector(
onTap: (){
model.closeKeyboard(context);
},
child: body,
);
}
return Stack(
children: <Widget>[
Positioned(top: 0,left: 00,bottom: 0,right: 0,child:
GestureDetector(
onTap: (){
model.closeKeyboard(context);
},
child: body,
),
),
Positioned(top: 0,left: 0,bottom: 0,right: 0,child:
ToolBar(height: toolBarHeight,
color: toolBarColor,
tintColor: toolBarTintColor,
focusNodeMap: model.focusNodeMap,
doneCallback: (){
// 點(diǎn)擊空白處的處理
model.closeKeyboard(context);
},)
),
],
);
}
}
鍵盤toolbar管理類ToolBar.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'dart:math' as math;
class ToolBarModel {
int index;
FocusNode focusNode;
ToolBarModel({this.index,this.focusNode});
}
class ToolBar extends StatefulWidget {
Map <String,ToolBarModel> focusNodeMap;
VoidCallback doneCallback;
double height=40;
Color color = Color(0xffeeeeee);
Color tintColor = Colors.blue;
ToolBar({this.focusNodeMap,this.doneCallback,this.height=40,this.color = const Color(0xffeeeeee),this.tintColor = Colors.blue});
@override
State<StatefulWidget> createState() {
return ToolBarState(focusNodeMap: focusNodeMap,
doneCallback: doneCallback,
height: height,
color: color,
tintColor: tintColor);
}
}
class ToolBarState extends State<ToolBar>{
Map <String,ToolBarModel> focusNodeMap;
VoidCallback doneCallback;
double height=40;
Color color = Color(0xffeeeeee);
Color tintColor = Colors.blue;
ToolBarState({this.focusNodeMap,this.doneCallback,this.height=40,this.color = const Color(0xffeeeeee),this.tintColor = Colors.blue});
@override
Widget build(BuildContext context) {
ToolBarModel barModel = currentEditingFocusNode();
if(barModel == null){
// 沒(méi)有任何輸入框處于編輯狀態(tài)赖临,則返回的是0高度的容器
return Column(children: <Widget>[
Flexible(child: Container()),
Container(height: 0)
],
);
}else{
return Column(children: <Widget>[
Flexible(child: Container()),
createToolBar(barModel)
],
);
}
}
Widget createToolBar(ToolBarModel barModel){
// 有輸入框在編輯狀態(tài)
int currentIndex = barModel.index;
bool isFirst = currentIndex==0;
bool isLast = currentIndex==(focusNodeMap.length-1);
// 前一個(gè)
Widget preIcon = Icon(Icons.arrow_forward_ios,
color: isFirst?Colors.grey:tintColor,size: 20.0,);
Widget preBtn = InkWell(
child:Transform(
transform: Matrix4.identity()..rotateZ(math.pi),// 旋轉(zhuǎn)的角度
origin: Offset(10,10),
child: preIcon
),
onTap: (){
focusNodeAtIndex(currentIndex-1);
},
);
// 下一個(gè)
Widget nextBtn = InkWell(
child:Icon(Icons.arrow_forward_ios,
color:isLast?Colors.grey:tintColor,
size: 20,),
onTap:(){
focusNodeAtIndex(currentIndex+1);
},
);
// 關(guān)閉
// Widget doneBtn = CupertinoButton(
// child: Container(height: 40,width: 200,child: Text('關(guān)閉')),
// onPressed: doneCallback
// );
Widget doneBtn = InkWell(
child: Text('關(guān)閉',style: TextStyle(color: tintColor),),
onTap: doneCallback
);
return Container(
height: height,color: color,
padding: EdgeInsets.only(left: 10,right: 10),
child: Row(
children: <Widget>[
preBtn,
SizedBox(width: 40,),
nextBtn,
Flexible(child: Container(),),
doneBtn
],
),
);
}
// 獲取當(dāng)前獲得焦點(diǎn)的對(duì)象
ToolBarModel currentEditingFocusNode(){
for(ToolBarModel barModel in focusNodeMap.values){
if(barModel.focusNode.hasFocus){
return barModel;
}
}
return null;
}
/// 讓指定的某個(gè)node獲得焦點(diǎn)
void focusNodeAtIndex(int selectIndex){
if(selectIndex<0||selectIndex>=focusNodeMap.length){
return;
}
for(ToolBarModel barModel in focusNodeMap.values){
if(selectIndex == barModel.index){
barModel.focusNode.requestFocus();
setState(() {
});
return;
}
}
}
}