【Flutter小技巧08】--- Flutter自定义键盘和系统键盘切换

3,327 阅读3分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。

Flutter小技巧目录
【Flutter小技巧01】--- TextField文本垂直居中
【Flutter小技巧02】Flutter环境变量配置
【Flutter小技巧03】-- 常见报错记录
【Flutter小技巧04】--- Flutter架构设计
【Flutter小技巧05】--- Flutter混编集成方案探讨
【Flutter小技巧06】--- Flutter折叠头像、毛玻璃效果、消息提示的实现
【Flutter小技巧07】--- Flutter生命周期

📃 需求是学习技术最有效的动力

一:前言:遇到需求,实现自定义键盘,同时和系统键盘切换。 image.png

image.png

二:实现步骤。 1、首页实现定义组输入组件和切换按钮 2、自定义键盘 3、实现交互 三:详细实现。
1、首页实现定义组输入组件和切换按钮,这个简单。直接贴完整代码。

Container(
    height: 50,
    color: Colors.white,
    child: Row(
      children: [
        Expanded(
          child: PaddingWidget(
            child: TextFieldWidget(
              hintText: '请输入药品拼音首字母',
              focusNode: focusNode ?? null,
              editingController: controller,
              autoFocus: autoFocus ?? true,
              showCursor: showCursor ?? true,
              readOnly: readOnly ?? true,
              onTap: () {
                if (onTap != null) {
                  onTap!();
                }
              },
              onSubmitted: (value) {
                if (onSubmitted != null) {
                  onSubmitted!(value);
                }
              },
              onChanged: (value) {
                if (onChanged != null) {
                  onChanged!(value);
                }
              },
            ),
            left: 15,
          ),
        ),
        Container(
          color: WMColor.divider,
          width: 0.5,
          height: 40,
        ),
        GestureDetectorWidget(
          child: Container(
              width: 60,
              height: 50,
              alignment: Alignment.center,
              // color: Colors.red,
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Icon(Icons.keyboard_sharp, color: Color(0xFF6D7380)),
                  TextWidget(
                    '系统键盘',
                    style: WMTextStyle.setTextStyle(Color(0xFF373E4D),
                        fontSize: 10),
                  ),
                ],
              )),
          clickCallBack: () {
            Utils.logs('切换键盘');
            if (switchKeyboardCallBack != null) {
              switchKeyboardCallBack!();
            }
          },
        )
      ],
    ));

2、自定义键盘:这里先参考大佬的自定义键键盘 (后期会改造成自定义字母键盘)blog.csdn.net/weixin_3802…


import 'package:flutter/material.dart';

/// <summary>
/// todo: 数字键盘
/// author:zwb
/// dateTime:2021/7/19 10:25
/// filePath:lib/app/widgets/number_keypan.dart
/// desc:
/// <summary>
OverlayEntry? overlayEntry;
numberKeypan({
  required Function(OverlayEntry) initialization,
  required Function(String) onTap,
  Function? onCommit,
  Function? onDel,
}) {
  overlayEntry = OverlayEntry(builder: (context) {
    List<String> list = [      '1',      '2',      '3',      '4',      '5',      '6',      '7',      '8',      '9',      '',      '0',      '.'    ];
    return Container(
      child: AnimatedContainer(
        curve: Cubic(0.160, 0.265, 0.125, 0.995),
        duration: Duration(milliseconds: 360),
        child: Positioned(
            bottom: 0,
            child: Material(
              child: Container(
                width: MediaQuery.of(context).size.width,
                alignment: Alignment.center,
                color: Colors.grey[200],
                child: Row(
                  children: [
                    Expanded(
                      child: Wrap(
                        alignment: WrapAlignment.spaceBetween,
                        children: List.generate(list.length, (index) {
                          return Material(
                            color: Colors.white,
                            child: Ink(
                              child: InkWell(
                                child: Container(
                                  decoration: BoxDecoration(
                                    border: Border.all(
                                        color: Colors.grey, width: 0.25),
                                  ),
                                  alignment: Alignment.center,
                                  height: 50,
                                  width:
                                      (MediaQuery.of(context).size.width - 60) /
                                          3,
                                  child: Text(
                                    "${list[index]}",
                                    style: TextStyle(
                                        fontSize: 18,
                                        fontWeight: FontWeight.bold),
                                  ),
                                ),
                                onTap: () {
                                  if (list[index] != "") {
                                    onTap(list[index]);
                                  }
                                },
                              ),
                              color: Colors.white,
                            ),
                          );
                        }),
                      ),
                    ),
                    Column(
                      children: [
                        SizedBox(
                          width: 60,
                          height: 50 * 1.5,
                          child: MaterialButton(
                            onPressed: () {
                              if (onDel != null) {
                                onDel();
                              }
                            },
                            child: Text("删除",
                                style: TextStyle(
                                    color: Colors.black,
                                    fontWeight: FontWeight.bold)),
                            color: Colors.grey[100],
                            elevation: 0,
                            padding: EdgeInsets.all(0),
                          ),
                        ),
                        SizedBox(
                          width: 60,
                          height: 50 * 2.5,
                          child: MaterialButton(
                            onPressed: () {
                              // disKeypan();
                              if (onCommit != null) {
                                onCommit();
                              }
                            },
                            child: Text(
                              "回车",
                              style: TextStyle(
                                  color: Colors.white,
                                  fontWeight: FontWeight.bold),
                            ),
                            color: Colors.blue,
                            elevation: 0,
                            padding: EdgeInsets.all(0),
                          ),
                        ),
                      ],
                    ),
                  ],
                ),
              ),
            )),
      ),
    );
  });
  initialization(overlayEntry!);
}

/// <summary>
/// todo: 保持光标在最后
/// author: zwb
/// date: 2021/7/19 11:43
/// param: 参数
/// return: void
/// <summary>
///
lastCursor({required TextEditingController textEditingController}) {
  /// 保持光标在最后
  final length = textEditingController.text.length;
  textEditingController.selection =
      TextSelection(baseOffset: length, extentOffset: length);
}

/// <summary>
/// todo: 自定义键盘的删除事件
/// author: zwb
/// date: 2021/7/19 11:45
/// param: 参数
/// return: void
/// <summary>
///
delCursor({required TextEditingController textEditingController}) {
  if (textEditingController != null && textEditingController.value.text != "")
    textEditingController.text = textEditingController.text
        .substring(0, textEditingController.text.length - 1);
}

/// <summary>
/// todo: 打开键盘
/// author: zwb
/// date: 2021/7/19 12:04
/// param: 参数
/// return: void
/// <summary>
///
openKeypan({BuildContext? context}) {
  Overlay.of(context!)!.insert(overlayEntry!);
}

/// <summary>
/// todo: 销毁键盘
/// author: zwb
/// date: 2021/7/19 12:03
/// param: 参数
/// return: void
/// <summary>
///
disKeypan() {
  overlayEntry!.remove();
}

3、实现交互

// 首先要要设置false,否则会弹起异常。弹起的时候我们使用动画,输入组件和键盘弹起,或者和自定义键盘一起弹起。
resizeToAvoidBottomInset: false,

// 核心弹出的代码。 可以在某个地方触发是否弹起键盘做一个标识。 
GetBuilder<CNPrescriptionController>(
  init: CNPrescriptionController(),
  builder: (_) {
    return Container(
      child: AnimatedContainer(
        curve: Cubic(0.160, 0.265, 0.125, 0.995),
        duration: Duration(milliseconds: 360),
        height: keyBoardType == 1
            ? _prescriptionC.medicineSearchList.isEmpty
                ? 250
                : 250 + 60
            : _prescriptionC.medicineSearchList.isEmpty
                ? MediaQuery.of(context).viewInsets.bottom +
                    50
                : MediaQuery.of(context).viewInsets.bottom +
                    50 +
                    60,
        child: Container(
          // height: keyBoardType == 1 ? 250 : 380,
          alignment: Alignment.topCenter,
          child: Column(
            children: [
              _prescriptionC.medicineSearchList.isEmpty
                  ? Container()
                  : CNPrescriptionResultWidget(
                      selectedCallBack: (index) {
                        _prescriptionC
                            .selectedSearchResultHandle(
                                index);
                      },
                    ),
              CNPrescriptionNameInputWidget(
                controller,
                switchKeyboardCallBack: () {
                  switchKeyboard();
                },
                focusNode: _focusNode,
                // showCursor: true,
                autoFocus: keyBoardType == 1 ? false : true,
                readOnly: keyBoardType == 1 ? true : false,
                onTap: () {
                  // switchKeyboard();
                },
                onSubmitted: (value) {
                  Utils.logs('回车');
                  _prescriptionC.isShowInput = false;
                  setState(() {});
                },
                onChanged: (value) {
                  _prescriptionC.search(value);
                },
              )
            ],
          ),
        ),
      ),
    );
  },
)

四、记录点点滴滴,后期还会改造更好。