Flutter几行代码处理点击空白关闭键盘及添加键盘ToolBar

上一篇:Flutter解决有输入框的页面,点击非输入框部分自动关闭键盘及键盘相关笔记

前言

在上一篇里接受了如何添加点击空白页面关闭键盘及展示键盘的ToolBar,现在对这两个功能封装成一个工具,让需要有这两个功能的页面几行代码就能集成相关功能

使用步骤:

Step1: 准备工作
BlankToolBarModel blankToolBarModel = BlankToolBarModel();

void initState() {
   // Step1.1: 焦点变化时的响应
   blankToolBarModel.outSideCallback = focusNodeChange;
   super.initState();
 }
 // Step1.2: 焦点变化时的响应操作
 void focusNodeChange(){
   setState(() {});
 }

@override
 void dispose() {
   // Step1.3: 在销毁页面时取消监听
   blankToolBarModel.removeFocusListeners();
   super.dispose();
 }
Step2: 由tool提供FocusNode创建TextField
// 创建输入行
 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创建body
@override
 Widget build(BuildContext context) {
   return Scaffold(
     appBar: AppBar(title: Text('登录'),),
     // Step4 用tool创建body
     body: BlankToolBarTool.blankToolBarWidget(
           context,
           model:blankToolBarModel,
           body:xxx这里真正创建的body展示内容xxxx
       ),
   );
 }

完整例子:

import 'package:BlankToolBarTool.dart';
import 'package:flutter/material.dart';

class LoginPage5 extends StatefulWidget {
  @override
  State createState() {
    return LoginPage5State();
  }
}

class LoginPage5State extends State{
  TextEditingController nameController = TextEditingController();
  TextEditingController pwdController = TextEditingController();
  TextEditingController codeController = TextEditingController();
  // Step1: 响应空白处的焦点的Node
  BlankToolBarModel blankToolBarModel = BlankToolBarModel();
  @override
  void initState() {
    // Step2.1: 焦点变化时的响应
    blankToolBarModel.outSideCallback = focusNodeChange;
    super.initState();
  }
  // Step2.2: 焦点变化时的响应操作
  void focusNodeChange(){
    setState(() {});
  }

  @override
  void dispose() {
    // Step3: 在销毁页面时取消监听
    blankToolBarModel.removeFocusListeners();
    super.dispose();
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('登录'),),
      // Step4 用tool创建body
      body: BlankToolBarTool.blankToolBarWidget(
            context,
            model:blankToolBarModel,
            body:createBody()
        ),
    );
  }

  Widget createBody(){
    return ListView(
      padding: EdgeInsets.only(left: 20,right: 20),
      children: [
        SizedBox(height: 30),
        createInputText(nameController,hint: '请输入用户名',icon: Icons.people),
        SizedBox(height: 30),
        createInputText(pwdController,hint: '请输入密码',icon: Icons.power,obscureText:true),
        SizedBox(height: 30),
        createInputText(codeController,hint: '请输验证码',icon: Icons.nature,obscureText:true),
        SizedBox(height: 30),
        FlatButton(color: Colors.blue,child: Text('登录'),onPressed: checkLogin,)
      ],
    );
  }

  // 创建输入行
  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 设置FocusNode
            focusNode: focusNode,
          );

    List rowList = [];
    // 输入框前的提示图标
    rowList.add(SizedBox(width: 10));
    rowList.add(Icon(icon));
    // 输入框
    rowList.add(Expanded(child: textField));
    
              
    return Row(children: rowList);
  }

  // 点击登录处理
  void checkLogin(){
    print(nameController.text);
    print(pwdController.text);
    print(codeController.text);
  }

}
自定义toolbar.gif

工具类BlankToolBarTool.dart

import 'ToolBar.dart';
import 'package:flutter/material.dart';

/// 用于持有FocusNode的类
class BlankToolBarModel {
  // 点击空白部分用于响应的FocusNode
  FocusNode blankModel=FocusNode();
  // 保存页面中所有InputText绑定的FocusNode
  Map focusNodeMap={};

  FocusNode _currentEditingNode;
  // 用于外侧的回调
  VoidCallback outSideCallback;
  BlankToolBarModel({this.outSideCallback});

  /**
   * 通过一个key获取node,一般是通过TextEditingController对象的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;
  }
  /**
   * 通过controller获取focusNode
   */
  FocusNode getFocusNodeByController(TextEditingController controller){
    String key = controller.hashCode.toString();
    return getFocusNode(key);
  }
  /**
   * 找到正处于编辑状态的FocusNode
   */
  FocusNode findEditingNode(){
    for(ToolBarModel barModel in focusNodeMap.values){
      if(barModel.focusNode.hasFocus){
        return barModel.focusNode;
      }
    }
    return null;
  }
  // 监听FocusNode变化
  Future focusNodeListener() async {
      FocusNode editingNode = findEditingNode();
      if(_currentEditingNode != editingNode){
        _currentEditingNode = editingNode;
        print('>>>>>>>>+++++++++++');
        if(outSideCallback != null){
          outSideCallback();
        }
      }else{
        print('>>>>>>>>----------');
      }
      
  }
  /// 移除所有监听
  void removeFocusListeners(){
    for(ToolBarModel barModel in focusNodeMap.values){
        barModel.focusNode.removeListener(focusNodeListener); 
      }
  }
  /// 关闭键盘
  void closeKeyboard(BuildContext context){
    FocusScope.of(context).requestFocus(blankModel);
  }
}
/**
 * 增加
 * 1、自动处理点击空白页面关闭键盘,
 * 2、键盘上方增加一个toolbar
 */
class BlankToolBarTool{
  static Widget blankToolBarWidget(
    // 上下文
    BuildContext context,
    {
      // 数据model
      BlankToolBarModel model,
      // 要展示的子内容
      Widget body,
      // 是否展示toolBar
      bool showToolBar = true,
      // 默认的toolBar的高度
      double toolBarHeight = 40,
      // toolBar的背景色
      Color toolBarColor = const Color(0xffeeeeee),
      // toolBar的可点击按钮的颜色
      Color toolBarTintColor = Colors.blue
    }
  ){
    if(!showToolBar){
      return GestureDetector(
              onTap: (){
                model.closeKeyboard(context);
              },
              child: body,
            );
    }
    return Stack(
         children: [
           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: (){
                      // 点击空白处的处理
                      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  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 createState() {
    return ToolBarState(focusNodeMap: focusNodeMap,
        doneCallback: doneCallback,
        height: height,
        color: color,
        tintColor: tintColor);
  }
}
class ToolBarState extends State{
  Map  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){
      // 没有任何输入框处于编辑状态,则返回的是0高度的容器
      return Column(children: [
               Flexible(child: Container()),
               Container(height: 0)
           ],
      );
    }else{
      return Column(children: [
               Flexible(child: Container()),
               createToolBar(barModel)
           ],
      );
    }
  }
  Widget createToolBar(ToolBarModel barModel){
    // 有输入框在编辑状态
    int currentIndex = barModel.index;
    bool isFirst = currentIndex==0;
    bool isLast = currentIndex==(focusNodeMap.length-1);
    // 前一个
    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),// 旋转的角度
        origin: Offset(10,10),
        child: preIcon
      ),
      onTap: (){
        focusNodeAtIndex(currentIndex-1);
      },
    );
    // 下一个
    Widget nextBtn = InkWell(
      child:Icon(Icons.arrow_forward_ios,
          color:isLast?Colors.grey:tintColor,
          size: 20,),
      onTap:(){
        focusNodeAtIndex(currentIndex+1);
      },
      );

    // 关闭
    // Widget doneBtn = CupertinoButton(
    //   child: Container(height: 40,width: 200,child: Text('关闭')),
    //   onPressed: doneCallback
    // );
    Widget doneBtn = InkWell(
      child: Text('关闭',style: TextStyle(color: tintColor),),
      onTap: doneCallback
    );
    
    return Container(
      height: height,color: color,
      padding: EdgeInsets.only(left: 10,right: 10),
      child: Row(
        children: [
          preBtn,
          SizedBox(width: 40,),
          nextBtn,
          Flexible(child: Container(),),
          doneBtn
        ],
      ),
    );
  }
  // 获取当前获得焦点的对象
  ToolBarModel currentEditingFocusNode(){
      for(ToolBarModel barModel in focusNodeMap.values){
        if(barModel.focusNode.hasFocus){
          return barModel;
        }
      }
      return null;
  }
  /// 让指定的某个node获得焦点
  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;
        }
      }
  }
}

你可能感兴趣的:(Flutter几行代码处理点击空白关闭键盘及添加键盘ToolBar)