Closed ghost closed 4 years ago
每一个页面都需要调用init的
:octocat: From gitme iOS
其它页面,比如是登录页面,没有NumberKeyboard.inputType的类型,需要吗?
其他页面不用的不需要
谢谢,解决了我的问题,
复现:在NumberKeyboard.inputType的输入框输入并完成,退出页面,然后在其它页面的字符输入框中,系统键盘可以呼出,但输入任何字符,但输入框没有输入内容。
目前我的解决方法是在页面的dispose中调用以下方法,虽然能解决,但感觉不是最好的方法。 在类CoolKeyboard中增加以下方法 static dispose(){ isInterceptor = false; BinaryMessages.setMockMessageHandler("flutter/textinput",null); }
在引用键盘的页面调用 void dispose() { CoolKeyboard.dispose();//销毁自定义键盘,不然其它页面输入不了 }
请大神有空看看。谢谢你及时解决上个问题(弹出键盘后返回上页后无法打开自定义键盘)
我也是自己加的这个dispose方法才解决的,不知道作者大大修复这个问题了没有,只要打开了自定义键盘的页面,如果不调用dispose这个方法,其他页面的输入框就无法输入了
复现:在NumberKeyboard.inputType的输入框输入并完成,退出页面,然后在其它页面的字符输入框中,系统键盘可以呼出,但输入任何字符,但输入框没有输入内容。
目前我的解决方法是在页面的dispose中调用以下方法,虽然能解决,但感觉不是最好的方法。 在类CoolKeyboard中增加以下方法 static dispose(){ isInterceptor = false; BinaryMessages.setMockMessageHandler("flutter/textinput",null); }
在引用键盘的页面调用 void dispose() { CoolKeyboard.dispose();//销毁自定义键盘,不然其它页面输入不了 }
请大神有空看看。谢谢你及时解决上个问题(弹出键盘后返回上页后无法打开自定义键盘)
确实这样可以解决问题。不同的表单页面,父级销毁了就会报这个错。
你好,我这边无法重现这个问题
同样的问题,如果我先调用自定义键盘然后再其他页面再调用系统键盘,那么系统键盘无法输入。
能否贴个例子代码,我这边无法重现,最好录制个视频
自定义车牌号输入键盘代码:
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。
问题已修复
复现:在NumberKeyboard.inputType的输入框输入并完成,退出页面,然后在其它页面的字符输入框中,系统键盘可以呼出,但输入任何字符,但输入框没有输入内容。
目前我的解决方法是在页面的dispose中调用以下方法,虽然能解决,但感觉不是最好的方法。 在类CoolKeyboard中增加以下方法 static dispose(){ isInterceptor = false; BinaryMessages.setMockMessageHandler("flutter/textinput",null); }
在引用键盘的页面调用 void dispose() { CoolKeyboard.dispose();//销毁自定义键盘,不然其它页面输入不了 }
请大神有空看看。谢谢你及时解决上个问题(弹出键盘后返回上页后无法打开自定义键盘)