Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NumberKeyboard.inputType的输入框切换到其它无法输入 #14

Closed
ghost opened this issue May 8, 2019 · 11 comments
Closed

NumberKeyboard.inputType的输入框切换到其它无法输入 #14

ghost opened this issue May 8, 2019 · 11 comments

Comments

@ghost
Copy link

ghost commented May 8, 2019

复现:在NumberKeyboard.inputType的输入框输入并完成,退出页面,然后在其它页面的字符输入框中,系统键盘可以呼出,但输入任何字符,但输入框没有输入内容。

目前我的解决方法是在页面的dispose中调用以下方法,虽然能解决,但感觉不是最好的方法。
在类CoolKeyboard中增加以下方法
static dispose(){
isInterceptor = false;
BinaryMessages.setMockMessageHandler("flutter/textinput",null);
}

在引用键盘的页面调用
void dispose() {
CoolKeyboard.dispose();//销毁自定义键盘,不然其它页面输入不了
}

请大神有空看看。谢谢你及时解决上个问题(弹出键盘后返回上页后无法打开自定义键盘)

@Im-Kevin
Copy link
Owner

Im-Kevin commented May 8, 2019

每一个页面都需要调用init的

:octocat: From gitme iOS

@ghost
Copy link
Author

ghost commented May 9, 2019

其它页面,比如是登录页面,没有NumberKeyboard.inputType的类型,需要吗?

@Im-Kevin
Copy link
Owner

其他页面不用的不需要

@kennenfromchina
Copy link

谢谢,解决了我的问题,

@kennenfromchina
Copy link

复现:在NumberKeyboard.inputType的输入框输入并完成,退出页面,然后在其它页面的字符输入框中,系统键盘可以呼出,但输入任何字符,但输入框没有输入内容。

目前我的解决方法是在页面的dispose中调用以下方法,虽然能解决,但感觉不是最好的方法。
在类CoolKeyboard中增加以下方法
static dispose(){
isInterceptor = false;
BinaryMessages.setMockMessageHandler("flutter/textinput",null);
}

在引用键盘的页面调用
void dispose() {
CoolKeyboard.dispose();//销毁自定义键盘,不然其它页面输入不了
}

请大神有空看看。谢谢你及时解决上个问题(弹出键盘后返回上页后无法打开自定义键盘)

我也是自己加的这个dispose方法才解决的,不知道作者大大修复这个问题了没有,只要打开了自定义键盘的页面,如果不调用dispose这个方法,其他页面的输入框就无法输入了

@Im-Kevin Im-Kevin reopened this Oct 15, 2019
@oh-jy
Copy link

oh-jy commented Oct 23, 2019

复现:在NumberKeyboard.inputType的输入框输入并完成,退出页面,然后在其它页面的字符输入框中,系统键盘可以呼出,但输入任何字符,但输入框没有输入内容。

目前我的解决方法是在页面的dispose中调用以下方法,虽然能解决,但感觉不是最好的方法。
在类CoolKeyboard中增加以下方法
static dispose(){
isInterceptor = false;
BinaryMessages.setMockMessageHandler("flutter/textinput",null);
}

在引用键盘的页面调用
void dispose() {
CoolKeyboard.dispose();//销毁自定义键盘,不然其它页面输入不了
}

请大神有空看看。谢谢你及时解决上个问题(弹出键盘后返回上页后无法打开自定义键盘)

确实这样可以解决问题。不同的表单页面,父级销毁了就会报这个错。

@Im-Kevin
Copy link
Owner

Im-Kevin commented Nov 9, 2019

你好,我这边无法重现这个问题

@chilimyan
Copy link

同样的问题,如果我先调用自定义键盘然后再其他页面再调用系统键盘,那么系统键盘无法输入。

@Im-Kevin
Copy link
Owner

能否贴个例子代码,我这边无法重现,最好录制个视频

@kennenfromchina
Copy link

kennenfromchina commented Nov 12, 2019

自定义车牌号输入键盘代码:

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

/// 每个按钮的高度
const double kBtnHeight = 48.0;

enum CarNumberInputType {
  /// 省份
  CarNumberInputTypeProvince,

  /// 字母和数字
  CarNumberInputTypeLetterAndDigital,
}

/// 车牌号输入键盘
class CarNumberKeyboard extends StatelessWidget {
  /// 自定义inputType类型
  static const CKTextInputType inputType =
      const CKTextInputType(name: 'CarNumberKeyboard');

  /// 获取键盘高度
  static double getHeight(BuildContext ctx) {
    return kBtnHeight * 5;
  }

  /// 键盘输入控制器
  final KeyboardController controller;

  /// 构造方法
  const CarNumberKeyboard({this.controller});

  /// 注册
  static register() {
    CoolKeyboard.addKeyboard(
      CarNumberKeyboard.inputType,
      KeyboardConfig(
        builder: (context, controller) {
          return CarNumberKeyboard(
            controller: controller,
          );
        },
        getHeight: CarNumberKeyboard.getHeight,
      ),
    );
  }

  /// 自定义视图
  @override
  Widget build(BuildContext context) {
    return CarNumberInput(
      carNumberInputType: controller.text.length < 1 ? CarNumberInputType.CarNumberInputTypeProvince : CarNumberInputType.CarNumberInputTypeLetterAndDigital,
      controller: this.controller,
    );
  }
}

class CarNumberInput extends StatefulWidget {
  ///控制器
  final KeyboardController controller;

  ///类型(省份/字母||数字)
  CarNumberInputType carNumberInputType;

  /// 构造方法
  CarNumberInput({
    Key key,
    @required this.controller,
    @required this.carNumberInputType,
  }) : super(key: key);

  @override
  _CarNumberInputState createState() => _CarNumberInputState();
}

class _CarNumberInputState extends State<CarNumberInput> {
  ///省份数组
  static const List<String> _provinceList = [
    '京',
    '津',
    '晋',
    '冀',
    '蒙',
    '辽',
    '吉',
    '黑',
    '沪',
    '苏',
    '浙',
    '皖',
    '闽',
    '赣',
    '鲁',
    '豫',
    '鄂',
    '湘',
    '粤',
    '桂',
    '琼',
    '渝',
    '川',
    '贵',
    '云',
    '藏',
    '陕',
    '甘',
    '青',
    '宁',
    '新',
    '使',
    '1',
    '2',
    '3',
    'W',
    'V',
    'K',
    'H',
    'B',
    'S',
    'L',
    'J',
    'N',
    'G',
    'C',
    'E',
    'Z',
  ];

  ///数字字母数组
  static const List<String> _letterAndDigitalList = [
    '1',
    '2',
    '3',
    '4',
    '5',
    '6',
    '7',
    '8',
    '9',
    '0',
    'Q',
    'W',
    'E',
    'R',
    'T',
    'Y',
    'U',
    'I',
    'O',
    'P',
    'A',
    'S',
    'D',
    'F',
    'G',
    'H',
    'J',
    'K',
    'L',
    '',
    'Z',
    'X',
    'C',
    'V',
    'B',
    'N',
    'M',
    '港',
    '澳',
    '',
    '学',
    '警',
    '挂',
    '领',
    '试',
    '超',
    '练',
    '使',
  ];

  /// 更新键盘类型
  void updateType() {
    var currentText = widget.controller.text;
    print(widget.controller.text);
    setState(() {
      if (currentText.length < 1) {
        widget.carNumberInputType =
            CarNumberInputType.CarNumberInputTypeProvince;
      } else {
        widget.carNumberInputType =
            CarNumberInputType.CarNumberInputTypeLetterAndDigital;
      }
    });
  }

  ///点击事件
  void _onBtnClick(String name) {
    widget.controller.addText(name);
    updateType();
  }

  /// 删除事件
  void _onDeleteClick() {
    widget.controller.deleteOne();
    updateType();
  }

  ///键盘视图
  Widget _showKeyBoard() {
    /// 临时数组
    List<String> tempList;
    if (widget.carNumberInputType ==
        CarNumberInputType.CarNumberInputTypeProvince) {
      tempList = _provinceList;
    } else {
      tempList = _letterAndDigitalList;
    }

    /// 最终Widgets数组
    List<Widget> provinceWidgets = List();

    /// 根据临时数组构造最终数组(添加空白视图和最后删除按钮)
    for (int i = 0; i < tempList.length; i++) {
      String name = tempList[i];
      if (name.length <= 0) {
        provinceWidgets.add(Container(
          color: Color(0xFFF2F2F2),
          width: MediaQuery.of(context).size.width / 10.0,
          height: kBtnHeight,
        ));
        continue;
      }
      provinceWidgets.add(
        Material(
          child: Container(
            child: Ink(
              color: Color(0xFFF2F2F2),
              width: MediaQuery.of(context).size.width / 10.0,
              height: kBtnHeight,
              child: Padding(
                padding: EdgeInsets.all(4.0),
                child: InkWell(
                  onTap: () => _onBtnClick(tempList[i]),
                  child: Ink(
                    decoration: name.length > 0
                        ? BoxDecoration(
                            color: Color(0xFFFFFFFF),
                            borderRadius: BorderRadius.circular(4.0),
                            border: Border.all(
                              color: Color(0xFFE4E4E4),
                              width: 1.0,
                            ),
                          )
                        : null,
                    child: Center(
                      child: Text(
                        name,
                        style: TextStyle(
                          fontSize: 17,
                          color: Color(0xFF333333),
                        ),
                      ),
                    ),
                  ),
                ),
              ),
            ),
          ),
        ),
      );
    }

    ///删除按钮
    provinceWidgets.add(Material(
      child: Container(
        child: Ink(
          color: Color(0xFFF2F2F2),
          width: MediaQuery.of(context).size.width / 5.0,
          height: kBtnHeight,
          child: Padding(
            padding: EdgeInsets.all(4.0),
            child: InkWell(
              onTap: widget.controller.text.length > 0
                  ? () {
                      _onDeleteClick();
                    }
                  : null,
              child: Ink(
                decoration: BoxDecoration(
                  color: Color(0xFFFFFFFF),
                  borderRadius: BorderRadius.circular(4.0),
                  border: Border.all(
                    color: Color(0xFFE4E4E4),
                    width: 1.0,
                  ),
                ),
                child: Center(
                  child: Icon(
                    Icons.backspace,
                    color: widget.controller.text.length > 0
                        ? Color(0xFF333333)
                        : Color(0xFF999999),
                  ),
                ),
              ),
            ),
          ),
        ),
      ),
    ));

    // TODO:解决wrap不能自动换行的临时方案
    List<Widget> temp = List<Widget>();
    for (int i = 0; i < 5; i++) {
      List<Widget> rowList = List<Widget>();
      for (int j = 0; j < 10; j++) {
        if (i == 4 && j > 8) continue;
        int index = i * 10 + j;
        Widget focus = provinceWidgets[index];
        rowList.add(focus);
      }
      temp.add(Row(
        children: rowList,
      ));
    }
//    /*
    return Column(
      children: <Widget>[
        temp[0],
        temp[1],
        temp[2],
        temp[3],
        temp[4],
      ],
    );
//    */
    /*
    return Wrap(
      children: provinceWidgets,
    );
    */
  }

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Container(
        height: kBtnHeight * 5,
        alignment: Alignment.bottomCenter,
        child: _showKeyBoard(),
      ),
    );
  }
}

使用自定义键盘代码:

/**
 * PROJECT_NAM: driver_custom
 * PACKAGE_NAME: HomePage.StoreService
 * NAME: order_dialog
 * Describe:
 *
 * Created by kennen on 2019-06-11.
 * Copyright (c) 2019 Zhilun (Hangzhou) Technology Co., Ltd. All rights reserved.
 */

import 'package:flutter/material.dart';
import 'package:driver_custom/utils/CarNumberKeyboard.dart';
import 'package:cool_ui/cool_ui.dart';
import 'package:driver_custom/common/colours.dart';
import 'package:driver_custom/utils/utils.dart';

typedef void CallBack(Map<String, dynamic> result);

Future showOrderDialog(
  BuildContext context, {
  @required CallBack callBack,
  bool needVCCode = false,
  String phone,
  String vcCode,
  String carNumber,
  String name,
  String remark,
}) async {
  if (phone == null) {
    phone = await UserUtil.getUserTelephone();
  }
  var result = await showDialog(
    context: context,
    barrierDismissible: false,
    builder: (BuildContext context) {
      return OrderDialog(
        needVCCode: needVCCode,
        phone: phone,
        vcCode: vcCode,
        carNumber: carNumber,
        name: name,
        remark: remark,
      );
    },
  );
  if (callBack != null && result != null) {
    callBack(result);
  }
}

class OrderDialog extends StatefulWidget {
  final bool needVCCode;
  final String phone;
  final String vcCode;
  final String carNumber;
  final String name;
  final String remark;

  OrderDialog({
    Key key,
    this.needVCCode,
    this.phone,
    this.vcCode,
    this.carNumber,
    this.name,
    this.remark,
  }) : super(key: key);

  @override
  _OrderDialogState createState() => _OrderDialogState();
}

class _OrderDialogState extends State<OrderDialog> {
  TextEditingController phoneController;
  TextEditingController vcCodeController;
  TextEditingController carNumberController;
  TextEditingController nameController;
  TextEditingController remarkController;

  @override
  void dispose() {
    phoneController.dispose();
    vcCodeController.dispose();
    carNumberController.dispose();
    nameController.dispose();
    remarkController.dispose();
    CoolKeyboard.clearKeyboard();
    //MARK: 销毁自定义键盘,不然其它页面输入不了
    CoolKeyboard.dispose();
    super.dispose();
  }

  @override
  void initState() {
    super.initState();
    phoneController = TextEditingController(text: widget.phone);
    phoneController.selection = TextSelection.fromPosition(
        TextPosition(offset: phoneController.text.length));

    vcCodeController = TextEditingController(text: widget.vcCode);
    carNumberController = TextEditingController(text: widget.carNumber);
    nameController = TextEditingController(text: widget.name);
    remarkController = TextEditingController(text: widget.remark);
  }

  @override
  Widget build(BuildContext context) {
    return KeyboardMediaQuery(
      child: Builder(builder: (BuildContext context) {
        CoolKeyboard.init(context);
        return Center(
          child: Container(
            padding: EdgeInsets.symmetric(horizontal: 4.0),
            width: MediaQuery.of(context).size.width - 32.0,
            height: MediaQuery.of(context).size.width - 32.0,
            decoration: BoxDecoration(
              color: Colors.white,
              borderRadius: BorderRadius.circular(4.0),
            ),
            child: Material(
              child: Column(
                children: <Widget>[
                  Expanded(
                    child: _buildListView(),
                  ),
                  _buildFooter(),
                ],
              ),
            ),
          ),
        );
      }),
    );
  }

  Widget _buildListView() {
    List<Widget> children = [];
    children.add(
      _buildItem(
        title: '手机:',
        placeholder: '请填写您的手机号码',
        isVCCode: false,
        keyboardType: TextInputType.phone,
        controller: phoneController,
      ),
    );
    if (widget.needVCCode) {
      children.add(
        _buildItem(
          title: '验证码:',
          placeholder: null,
          isVCCode: true,
          keyboardType: TextInputType.number,
          controller: vcCodeController,
        ),
      );
    }
    children.add(
      _buildItem(
        title: '车牌:',
        placeholder: '请填写您的车牌',
        isVCCode: false,
        keyboardType: CarNumberKeyboard.inputType,
        controller: carNumberController,
      ),
    );
    children.add(
      _buildItem(
        title: '姓名:',
        placeholder: '请填写您的姓名(选填)',
        isVCCode: false,
        controller: nameController,
      ),
    );
    children.add(
      _buildItem(
        title: null,
        placeholder: null,
        isVCCode: false,
        controller: remarkController,
      ),
    );
    return ListView(
      children: children,
    );
  }

  Widget _buildItem({
    @required String title,
    @required String placeholder,
    @required bool isVCCode,
    TextInputType keyboardType,
    @required TextEditingController controller,
  }) {
    int maxLines = 1;
    if (title == null) {
      maxLines = 3;
      placeholder = '请填写备注(选填)';
      keyboardType = TextInputType.text;
    } else if (isVCCode) {
      placeholder = '请填写您的验证码';
      keyboardType = TextInputType.number;
    }
    TextField textField = TextField(
      controller: controller,
      keyboardType: keyboardType,
      maxLines: maxLines,
      maxLength: title == "手机:" ? 11 : (title == "车牌:" ? 8 : 50),
      decoration: InputDecoration(
        hintText: placeholder,
        border: InputBorder.none,
        counterText: title == null ? "50" : "",
      ),
      style: TextStyle(
        fontSize: 14.0,
        color: Colours.text_color,
      ),
//      onChanged: (String res) {
//        if (controller == phoneController) {
//          if (res.trim().length > 11) {
//            controller.text = controller.text.substring(0, 11);
//          }
//        } else if (controller == carNumberController ||
//            controller == nameController ||
//            controller == vcCodeController) {
//          if (res.trim().length > 10) {
//            controller.text = controller.text.substring(0, 10);
//          }
//        }
//      },
    );
    List<Widget> children = [];
    if (title != null) {
      children.add(Container(
        width: 60.0,
        child: Text(
          title,
          style: TextStyle(
            fontSize: 14.0,
            color: Colours.title_color,
            decoration: TextDecoration.none,
          ),
        ),
      ));
    }
    children.add(Expanded(child: textField));
    if (isVCCode) {
      children.add(
        Container(
          width: 100.0,
          height: 32.0,
          decoration: BoxDecoration(
            borderRadius: BorderRadius.circular(4.0),
            border: Border.all(color: Colours.border_color, width: 1.0),
          ),
          child: Center(
            child: Text(
              '获取验证码',
              style: TextStyle(fontSize: 14.0, color: Colours.text_color),
            ),
          ),
        ),
      );
    }
    return Container(
      height: title != null ? 48.0 : null,
      padding: EdgeInsets.symmetric(horizontal: 12.0),
      decoration: title != null
          ? UnderlineTabIndicator(
              borderSide: BorderSide(color: Colours.border_color, width: 1.0))
          : null,
      child: Row(
        children: children,
      ),
    );
  }

  Widget _buildFooter() {
    return Row(
      children: <Widget>[
        Expanded(
          child: FlatButton(
            padding: null,
            onPressed: () {
              Navigator.pop(context);
            },
            child: Text(
              '取消',
              style: TextStyle(
                fontSize: 14.0,
                color: Colours.title_color,
                decoration: TextDecoration.none,
              ),
            ),
          ),
        ),
        Expanded(
          child: FlatButton(
            padding: null,
            onPressed: () {
              _checkData();
            },
            child: Text(
              '确认下单',
              style: TextStyle(
                fontSize: 14.0,
                color: Colours.title_color,
                decoration: TextDecoration.none,
              ),
            ),
          ),
        ),
      ],
    );
  }

  /// 校验数据
  void _checkData() async {
    if (!RegexUtil.isMobileSimple(phoneController.text.trim())) {
      showCenterToast('请输入正确的手机号');
      return;
    }
    if (!RegexUtil.isCarNumber(carNumberController.text.trim())) {
      showCenterToast('请输入正确的车牌号');
      return;
    }

    Map<String, String> result = {};
    result['phone'] = phoneController.text.trim() ?? null;
    result['vcCode'] = vcCodeController.text.trim() ?? null;
    result['carNumber'] = carNumberController.text.trim() ?? null;
    result['name'] = nameController.text.trim() ?? null;
    result['remark'] = remarkController.text.trim() ?? null;
    print(result.toString());
    Navigator.pop(context, result);
  }
}

其它页面正常使用TextField,就会出现无法输入的bug。

复现bug视频链接

@Im-Kevin
Copy link
Owner

问题已修复

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants