• Flutter实战-自定义键盘(二)


    8ee0b048ce2560dbfa69e5e56d294b88.jpeg

    用了两年的flutter,有了一些心得,从今天开始陆续更新一些案例,不虚头巴脑,只求实战有用,以供学习或使用flutter的小伙伴参考,学习尚浅,如有不正确的地方还望各路大神指正,以免误人子弟,在此拜谢~(原创不易,转发请标注来源和作者)

    注意:无特殊说明,flutter版本为3.0+

    此文大部分代码内容来自 https://github.com/Im-Kevin/cool_ui,感谢大神指路,喜欢的可以去看源码,当然也有区别于原作者的实现,敬请关注。


            第一篇文章中,我们介绍了如何像系统键盘一样推起组件,那么这一篇中我们看一下初始化中做了哪些操作

    实现数字键盘第一步后,那么我们下一步关键点就是如何监听输入,我们知道Flutter是通过原生通道向Android和ios系统发送指令的,比如键盘的输入一个值是调用"flutter/textinput"向原生发送输入指令的。

    一。键盘初始化

    初始化中加一个拦截器,用我们自身的方式处理

    static init(KeyboardRootState root, BuildContext context) {
    _root = root;
    _context = context;
    interceptorInput();  //键盘的拦截,
    }

    static interceptorInput() {
    if (isInterceptor) return;
    isInterceptor = true;
    WidgetsBinding.instance.defaultBinaryMessenger
    .setMessageHandler("flutter/textinput", _textInputHanlde); //使用自身的处理方式
    }

    这里有重要概念BinaryMessenger,这是个抽象类,官方解释如下

    /// A messenger which sends binary data across the Flutter platform barrier.

    我们可以覆盖他的setMessageHandler方法去处理,我么实现的是键盘,那么覆盖的就是”flutter/textinput”的处理方法。

    二。关键方法覆盖

    1. 'TextInput.show'

    TextField 获取焦点后调用该方法,那么此方法中我们要打开键盘

    static openKeyboard() {
    var keyboardHeight = _currentKeyboard!.getHeight(_context!); //获取配置高度
    _keyboardHeightNotifier.value = keyboardHeight;
    if (_root!.hasKeyboard && _pageKey != null) return;
    _pageKey = GlobalKey();
    var tempKey = _pageKey;
    _root!.setKeyboard((ctx) {
    if (_currentKeyboard != null && _keyboardHeightNotifier.value != 0) {
        return KeyboardPage(
            key: tempKey,
            builder: (ctx) {
            return _currentKeyboard!
            .builder(ctx, _keyboardController!, _keyboardParam);
        },height: _keyboardHeightNotifier.value);
        } else {
        return Container();
        }
    });

            打开键盘的逻辑就是添加一个builder,这个builder是键盘页面,并设置高度,并赋值给_keyboardHeightNotifier,这个在上一篇有讲过,会自动覆盖viewInsets的值,添加系统级别的遮盖

    2. 'TextInput.hide'

    隐藏键盘,调用root!.clearKeyboard(),也就是讲builder设置为空。

    3. 'TextInput.setClient'

    在TextInput.setClient中根据输入框定义的键盘类型找出对应键盘对应的键盘配置,以及初始输入变更监听KeyboardController。

    这时候我们可以自定义我们的类型和KeyboardController,用于响应我们自己的键盘事件。

    关键代码如下

    _keyboardController = KeyboardController(client: client!)
    ..addListener(() {
    var callbackMethodCall = MethodCall(
    "TextInputClient.updateEditingState", [
    _keyboardController!.client.connectionId,
    _keyboardController!.value.toJSON()
    ]);
    WidgetsBinding.instance.defaultBinaryMessenger
    .handlePlatformMessage("flutter/textinput",
    _codec.encodeMethodCall(callbackMethodCall), (data) {});
    });

    三。KeyboardController

    控制文字的输入,和实现一系列的按钮

    addText(),deleteOne(),用于输入和删除字符,还有换行,完成等操作

    /// 完成
    doneAction() {
    CoolKeyboard.sendPerformAction(TextInputAction.done);
    }

    /// 下一个
    nextAction() {
    CoolKeyboard.sendPerformAction(TextInputAction.next);
    }

    /// 上一个
    preAction() {
    CoolKeyboard.sendPerformAction(TextInputAction.previous);
    }

    其中sendPerformAction 会调用原生通道"TextInputClient.performAction",用于响应键盘非输入操作,这些操作定义在text_input.dart中。

    static sendPerformAction(TextInputAction action) {


    var callbackMethodCall = MethodCall("TextInputClient.performAction",
    [_keyboardController!.client.connectionId, action.toString()]);


    WidgetsBinding.instance.defaultBinaryMessenger.handlePlatformMessage(
    "flutter/textinput",
    _codec.encodeMethodCall(callbackMethodCall),
    (data) {});
    }

    四。实现键盘组件

    这个应该是全文最简单的部分,也是最基础的部分,用Row和Column实现横排竖排按钮

    用controller.deleteOne() 实现删除用

    controller.nextAction() 实现换行

    用controller.doneAction() 实现删完成

    问题:在实现过程中遇到一个问题,就是我所有的按钮都使用onTap实现点击事件,在发生连续点击的时候就会有字符丢失的情况

    解决方案

    GestureDetector(

    onPanDown: (details) {
    controller.addText(value ?? title);
    },

    onPanDown,触碰屏幕的时候调用,会优先onTap执行,具体的解释可以参考GestureDetector的源码,一共有7大类25种。

  • 相关阅读:
    ubuntu从源码编译gdal
    uniapp使用scroll-into-view实现锚点定位和滚动监听功能【楼层效果 / 侧边导航联动效果】
    基于51单片机霍尔传感器测速(仿真+源程序)
    node.js基于vue框架潮牌官网设计与实现毕业设计源码010955
    Nginx的反向代理、动静分离、负载均衡
    DEJA_VU3D - Cesium功能集 之 068-空间坐标系之箭头
    非关系型数据库之Mongodb简介
    设计模式之责任链模式(场景说明)
    后台管理系统项目-中
    Golang字符串分割、判断是否包含指定字符串
  • 原文地址:https://blog.csdn.net/hantian616/article/details/125908734