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

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

前言

在原生App开放中有个常见的功能,那就是当点击输入框时键盘弹出,同时输入框上移到键盘上方,同时点击非输入框的空白部分时,键盘自动关闭,同时在键盘的上方有一个ToolBar,可以点击上一个、下一个切换输入框

1、解决点击非输入框的地方关闭键盘
解决思路:将Scaffold的body设置成GestureDetector,点击空白处时就将焦点响应设置成自定义的FocusNode

import 'package:flutter/material.dart';

class LoginPage3 extends StatefulWidget {
  @override
  State createState() {
    return LoginPage3State();
  }
}

class LoginPage3State extends State{
  // 响应空白处的焦点的Node
  FocusNode blankNode = FocusNode();
  TextEditingController nameController = TextEditingController();
  TextEditingController pwdController = TextEditingController();

  @override
  void initState() {
    super.initState();
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('登录'),),
      body: GestureDetector(
              onTap: (){
                // 点击空白页面关闭键盘
                FocusScope.of(context).requestFocus(blankNode);
              },
              child: 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),
        FlatButton(color: Colors.blue,child: Text('登录'),onPressed: checkLogin,)
      ],
    );
  }

  // 创建输入行
  Widget createInputText(TextEditingController controller,{obscureText: false,String hint,IconData icon}){
    // 输入框
    TextField textField = TextField(
            controller: controller,
            keyboardType: TextInputType.text,
            decoration: InputDecoration(
              contentPadding: EdgeInsets.all(10.0),
              hintText: hint,
            ),
            obscureText: obscureText,
          );

    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);
  }

}
点击空白页面关闭键盘.gif

2、解决在键盘弹出时一起出现一个ToolBar
在上一个键盘的基础上添加一个toolbar,原理是使用给每个输入框都绑定一个FocusNode,同时使用Stack,Column,Flexible,根据是否有处于焦点的node动态设置是否显示toolbar

import 'dart:math' as math;

import 'package:flutter/material.dart';

class LoginPage4 extends StatefulWidget {
  @override
  State createState() {
    return LoginPage4State();
  }
}

class LoginPage4State extends State{
  // 响应空白处的焦点的Node
  FocusNode blankNode = FocusNode();
  Map nodeMap = {};
  TextEditingController nameController = TextEditingController();
  TextEditingController pwdController = TextEditingController();

  @override
  void initState() {
    super.initState();
  }
  @override
    void dispose(){
        for(Map map in nodeMap.values){
          FocusNode focusNode = map['node'];
          focusNode.removeListener(focusNodeListener); 
        }
        super.dispose();
    }
    Future focusNodeListener() async {  
      // 用async的方式实现这个listener
    }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('登录'),),
      body: Stack(
        children: [
          Positioned(top: 0,left: 0,bottom: 0,right: 0,
                    child: GestureDetector(
                        onTap: blankClicked,
                        child: createBody(),
                      ),
            ),
          Positioned(top: 0,left: 0,bottom: 0,right: 0,
                    child: Column(
                        children: [
                                Flexible(child: Container()),
                              createToolBar()
                          ],
                        ),
                ),
          
        ],
      )
    );
  }
  // 点击了空白的地方
  void blankClicked(){
    // 点击空白页面关闭键盘
    FocusScope.of(context).requestFocus(blankNode);
  }
  Map currentEditingFocusNode(){
      for(Map map in nodeMap.values){
        FocusNode focusNode = map['node'];
        if(focusNode.hasFocus){
          return map;
        }
      }
      return null;
  }
  void focusNodeAtIndex(int selectIndex){
    for(Map map in nodeMap.values){
        int index = map['index'];
        if(selectIndex == index){
          FocusNode focusNode = map['node'];
          focusNode.requestFocus();
          return;
        }
      }
  }
  Widget createToolBar(){
    Map map = currentEditingFocusNode();
    if(map == null){
      return Container(height: 0);
    }
    int currentIndex = map['index'];
    bool isFirst = currentIndex==0;
    bool isLast = currentIndex==(nodeMap.length-1);

    Widget preBtn = Transform(
      transform: Matrix4.identity()..rotateZ(math.pi),// 旋转的角度
      origin: Offset(10,10),
      child: Icon(Icons.arrow_forward_ios, 
      color: isFirst?Colors.grey:Colors.blue,size: 20.0,)
    );
    Widget nextBtn = Icon(Icons.arrow_forward_ios,
    color:isLast?Colors.grey:Colors.blue,size: 20,);
    return Container(
      height: 40,
      color: Color(0xffeeeeee),
      padding: EdgeInsets.only(left: 10,right: 10),
      child: Row(
        children: [
          InkWell(
            child: preBtn,onTap: (){
              // 点击上一个
            if(!isFirst){
              focusNodeAtIndex(currentIndex-1);
            }
          },),
          SizedBox(width: 40,),
          InkWell(
            child: nextBtn,onTap: (){
              // 点击下一个
            if(!isLast){
              focusNodeAtIndex(currentIndex+1);
            }
          },),
          Flexible(child: Container(),),
          InkWell(child: Text('关闭',style: TextStyle(color: Colors.blue,)),onTap: blankClicked),
        ],
      ),
    );
  }
  // 创建展示内容
  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),
        FlatButton(color: Colors.blue,child: Text('登录'),onPressed: checkLogin,)
      ],
    );
  }

  // 创建输入行
  Widget createInputText(TextEditingController controller,{obscureText: false,String hint,IconData icon}){
    // controller的唯一code
    String key = controller.hashCode.toString();
    Map map = nodeMap[key];
    FocusNode focusNode;
    if(map == null){
      focusNode = FocusNode();
      map = {};
      map['node'] = focusNode;
      map['index'] = nodeMap.length;
      focusNode.addListener(focusNodeListener);
      nodeMap[key] = map;
    }else{
      focusNode = map['node'];
    }
    // 输入框
    TextField textField = TextField(
            controller: controller,
            keyboardType: TextInputType.text,
            decoration: InputDecoration(
              contentPadding: EdgeInsets.all(10.0),
              hintText: hint,
            ),
            obscureText: obscureText,
            focusNode: focusNode,
            keyboardAppearance:Brightness.light
          );

    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);
  }

}
空白关闭toolbar.gif

你可能感兴趣的:(Flutter解决有输入框的页面,点击非输入框部分自动关闭键盘及键盘相关笔记)