内容简介:大家好,我又来了。 今年这个冬天真的是“寒冬”啊,我是真的被“冻伤”了,一年的计划全部被打算了,贼无奈,也让我遭受了一定的打击,希望之光在哪?(吐槽到此为止) 回到咱们的正题,刚用Flutter做完一个金融项目,当中使用到了类似于微信,和支付宝的那种密码输入框,然后为了安全一点也自己实现了自定义的键盘,今天跟大家分享一波效果如下图所示:当中的布局形式,大家可根据自己的具体需求来调整就好了,我这里写的demo是这样的布局,这个调整起来很简单(本来想弄成gif的,然而不会。。。)。
大家好,我又来了。 今年这个冬天真的是“寒冬”啊,我是真的被“冻伤”了,一年的计划全部被打算了,贼无奈,也让我遭受了一定的打击,希望之光在哪?(吐槽到此为止) 回到咱们的正题,刚用Flutter做完一个金融项目,当中使用到了类似于微信,和支付宝的那种密码输入框,然后为了安全一点也自己实现了自定义的键盘,今天跟大家分享一波
效果展示
效果如下图所示:
当中的布局形式,大家可根据自己的具体需求来调整就好了,我这里写的demo是这样的布局,这个调整起来很简单(本来想弄成gif的,然而不会。。。)。
分析一波
我们分析下这个东东,首先我们需要自定义好这个密码输入框,当我们在输入一个密码的时候,密码输入框就填充一位 ,这个过程其实我们自己把它绘制出来就好:
- 先绘制六个密码框
- 接受调用者传过来的密码,根据密码长度来绘制密码框的填充个数
输入框实现
/// 自定义 密码输入框 第一步 —— 使用画笔画出单个的框 class CustomJPasswordField extends StatelessWidget { /// 传入当前密码 String data; CustomJPasswordField(this.data); @override Widget build(BuildContext context) { return CustomPaint( painter: MyCustom(data), ); } } /// 继承CustomPainter ,来实现自定义图形绘制 class MyCustom extends CustomPainter { /// 传入的密码,通过其长度来绘制圆点 String pwdLength; MyCustom(this.pwdLength); /// 此处Sizes是指使用该类的父布局大小 @override void paint(Canvas canvas, Size size) { // 密码画笔 Paint mPwdPaint; Paint mRectPaint; // 初始化密码画笔 mPwdPaint = new Paint(); mPwdPaint..color = Colors.black; // mPwdPaint.setAntiAlias(true); // 初始化密码框 mRectPaint = new Paint(); mRectPaint..color = Color(0xff707070); /// 圆角矩形的绘制 RRect r = new RRect.fromLTRBR( 0.0, 0.0, size.width, size.height, new Radius.circular(size.height / 12)); /// 画笔的风格 mRectPaint.style = PaintingStyle.stroke; canvas.drawRRect(r, mRectPaint); /// 将其分成六个 格子(六位支付密码) var per = size.width / 6.0; var offsetX = per; while (offsetX < size.width) { canvas.drawLine( new Offset(offsetX, 0.0), new Offset(offsetX, size.height), mRectPaint); offsetX += per; } /// 画实心圆 var half = per/2; var radio = per/8; mPwdPaint.style = PaintingStyle.fill; /// 当前有几位密码,画几个实心圆 for(int i =0; i< pwdLength.length && i< 6; i++){ canvas.drawArc(new Rect.fromLTRB(i*per+half-radio, size.height/2-radio, i*per+half+radio, size.height/2+radio), 0.0, 2*pi, true, mPwdPaint); } } @override bool shouldRepaint(CustomPainter oldDelegate) { return true; } } 复制代码
自定义键盘
到这里为止,我们就写完了我们第一个重头,自定义的密码输入框,然后第二步,实现自定义密码键盘,密码键盘也可以通过完全自定义绘制出来,但是我这里用的一种比较简单的实现方式,直接使用多个按钮组装成一个键盘,
这个键盘其实就是12个相同样式的按钮组成,只是各自的文字内容不同,因此我们首先可以定义好一个公共的按钮样式,然后我们在其中通过回调的方式来将点击事件抛给调用者定义,
import 'package:flutter/material.dart'; /// 自定义 键盘 按钮 class CustomKbBtn extends StatefulWidget { /// 按钮显示的文本内容 String text; CustomKbBtn({Key key, this.text, this.callback}) : super(key: key); /// 按钮 点击事件的回调函数 final callback; @override State<StatefulWidget> createState() { return ButtonState(); } } class ButtonState extends State<CustomKbBtn> { ///回调函数执行体 var backMethod; void back() { widget.callback('$backMethod'); } @override Widget build(BuildContext context) { /// 获取当前屏幕的总宽度,从而得出单个按钮的宽度 MediaQueryData mediaQuery = MediaQuery.of(context); var _screenWidth = mediaQuery.size.width; return new Container( height:50.0, width: _screenWidth / 3, child: new OutlineButton( // 直角 shape: new RoundedRectangleBorder( borderRadius: new BorderRadius.circular(0.0)), // 边框颜色 borderSide: new BorderSide(color: Color(0x10333333)), child: new Text( widget.text, style: new TextStyle(color: Color(0xff333333), fontSize: 20.0), ), // 按钮点击事件 onPressed: back, )); } } 复制代码
自定义键盘代码实现
有了按钮之后,我们就将它拼装成一个完整的键盘:
/// 自定义密码 键盘 class MyKeyboard extends StatefulWidget { final callback; MyKeyboard(this.callback); @override State<StatefulWidget> createState() { return new MyKeyboardStat(); } } class MyKeyboardStat extends State<MyKeyboard> { final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>(); /// 定义 确定 按钮 接口 暴露给调用方 ///回调函数执行体 var backMethod; void onCommitChange() { widget.callback(new KeyEvent("commit")); } void onOneChange(BuildContext cont) { widget.callback(new KeyEvent("1")); } void onTwoChange(BuildContext cont) { widget.callback(new KeyEvent("2")); } void onThreeChange(BuildContext cont) { widget.callback(new KeyEvent("3")); } void onFourChange(BuildContext cont) { widget.callback(new KeyEvent("4")); } void onFiveChange(BuildContext cont) { widget.callback(new KeyEvent("5")); } void onSixChange(BuildContext cont) { widget.callback(new KeyEvent("6")); } void onSevenChange(BuildContext cont) { widget.callback(new KeyEvent("7")); } void onEightChange(BuildContext cont) { widget.callback(new KeyEvent("8")); } void onNineChange(BuildContext cont) { widget.callback(new KeyEvent("9")); } void onZeroChange(BuildContext cont) { widget.callback(new KeyEvent("0")); } /// 点击删除 void onDeleteChange() { widget.callback(new KeyEvent("del")); } @override Widget build(BuildContext context) { return new Container( key: _scaffoldKey, width: double.infinity, height: 250.0, color: Colors.white, child: new Column( children: <Widget>[ new Container( height:30.0, color: Colors.white, alignment: Alignment.center, child: new Text( '下滑隐藏', style: new TextStyle(fontSize: 12.0, color: Color(0xff999999)), ), ), /// 键盘主体 new Column( children: <Widget>[ /// 第一行 new Row( children: <Widget>[ CustomKbBtn( text: '1', callback: (val) => onOneChange(context)), CustomKbBtn( text: '2', callback: (val) => onTwoChange(context)), CustomKbBtn( text: '3', callback: (val) => onThreeChange(context)), ], ), /// 第二行 new Row( children: <Widget>[ CustomKbBtn( text: '4', callback: (val) => onFourChange(context)), CustomKbBtn( text: '5', callback: (val) => onFiveChange(context)), CustomKbBtn( text: '6', callback: (val) => onSixChange(context)), ], ), /// 第三行 new Row( children: <Widget>[ CustomKbBtn( text: '7', callback: (val) => onSevenChange(context)), CustomKbBtn( text: '8', callback: (val) => onEightChange(context)), CustomKbBtn( text: '9', callback: (val) => onNineChange(context)), ], ), /// 第四行 new Row( children: <Widget>[ CustomKbBtn(text: '删除', callback: (val) => onDeleteChange()), CustomKbBtn( text: '0', callback: (val) => onZeroChange(context)), CustomKbBtn(text: '确定', callback: (val) => onCommitChange()), ], ), ], ) ], ), ); } } 复制代码
这里的回调函数,其实是将所有的按钮事件处理交给调用者自己去处理, 这里就引出了代码中的KeyEvent()这个类,我们看看这个类的实现
/// 支符密码 用于 密码输入框和键盘之间进行通信 class KeyEvent { /// 当前点击的按钮所代表的值 String key; KeyEvent(this.key); bool isDelete() => this.key == "del"; bool isCommit() => this.key == "commit"; } 复制代码
这个类实际上只是拿到了按钮最终代表的实际内容,然后调用者可以根据这个key的值来判断当前点击的是 数字按钮 还是说是 删除按钮 或者是 确定按钮,以此来进行密码的修改,。
到这里为止,所有的内容基本都准备好了,接下来就是使用了: 这里得注意一个点,密码键盘是从屏幕的最下方弹出来的,这里我使用到了Flutter的showBottomSheet,这个是一个官方的widget,通过这个来实现键盘的弹出。
直接上代码吧
/// 支付密码 + 自定义键盘 class main_keyboard extends StatefulWidget { static final String sName = "enter"; @override State<StatefulWidget> createState() { return new keyboardState(); } } class keyboardState extends State<main_keyboard> { /// 用户输入的密码 String pwdData = ''; /* GlobalKey:整个应用程序中唯一的键 ScaffoldState:Scaffold框架的状态 解释:_scaffoldKey的值是Scaffold框架状态的唯一键 */ final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>(); // VoidCallback:没有参数并且不返回数据的回调 VoidCallback _showBottomSheetCallback; @override void initState() { _showBottomSheetCallback = _showBottomSheet; } @override Widget build(BuildContext context) { return new Scaffold( key: _scaffoldKey, body: _buildContent(context), ); } Widget _buildContent(BuildContext c) { return new Container( width: double.maxFinite, height: 300.0, color: Color(0xffffffff), child: new Column( children: <Widget>[ new Padding( padding: const EdgeInsets.only(top: 50.0), child: new Text( '请在此输入新支付密码', style: new TextStyle(fontSize: 18.0, color: Color(0xff333333)), ), ), ///密码框 new Padding( padding: const EdgeInsets.only(top: 15.0), child: _buildPwd(pwdData), ), ], ), ); } /// 密码键盘 确认按钮 事件 void onAffirmButton() { } /// 密码键盘的整体回调,根据不同的按钮事件来进行相应的逻辑实现 void _onKeyDown(KeyEvent data){ // 如果点击了删除按钮,则将密码进行修改 if (data.isDelete()) { if (pwdData.length > 0) { pwdData = pwdData.substring(0, pwdData.length - 1); setState(() {}); } } // 点击了确定按钮时 else if (data.isCommit()) { if (pwdData.length != 6) { // Fluttertoast.showToast(msg: "密码不足6位,请重试", gravity: ToastGravity.CENTER); return; } onAffirmButton(); } //点击了数字按钮时 将密码进行完整的拼接 else { if (pwdData.length < 6) { pwdData += data.key; } setState(() {}); } } /// 底部弹出 自定义键盘 下滑消失 void _showBottomSheet() { setState(() { // disable the button // 禁用按钮 _showBottomSheetCallback = null; }); /* currentState:获取具有此全局键的树中的控件状态 showBottomSheet:显示持久性的质感设计底部面板 解释:联系上文,_scaffoldKey是Scaffold框架状态的唯一键,因此代码大意为, 在Scaffold框架中显示持久性的质感设计底部面板 */ _scaffoldKey.currentState .showBottomSheet<void>((BuildContext context) { /// 将自定义的密码键盘作为其child 这里将回调函数传入 return new MyKeyboard(_onKeyDown); }) .closed .whenComplete(() { if (mounted) { setState(() { // re-enable the button // 重新启用按钮 _showBottomSheetCallback = _showBottomSheet; }); } }); } /// 构建 密码输入框 定义了其宽度和高度 Widget _buildPwd(var pwd) { return new GestureDetector( child: new Container( width: 250.0, height:40.0, // color: Colors.white, 自定义密码输入框的使用 child: new CustomJPasswordField(pwd), ), // 用户点击输入框的时候,弹出自定义的键盘 onTap: () { _showBottomSheetCallback(); }, ); } } 复制代码
大功告成,这个时候我们就实现了想要的效果啦。 回想了下我写的博客,基本都是代码偏多,我把该有的说明都在代码中写成注释了,我觉得这样更加的直观,希望各位喜欢这种方式,如果本文帮助到了你,希望你能点点喜欢,给我一点点鼓励,每次看到有人评论和点了喜欢,都会很开心,哈哈。要是能点点关注就更好了。
有啥问题欢迎及时联系我,我们下次再见啦!
以上所述就是小编给大家介绍的《Flutter仿微信,支付宝密码输入框+自定义键盘》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Swift自定义表情键盘+录音
- Kotlin–›自定义实现支付密码数字键盘
- 如何从iOS应用程序的自定义键盘检索击键?
- Android获取软键盘的高度、键盘的打开与关闭、监听键盘处于打开还是关闭状态
- ios 最新系统bug与解决——微信公众号中弹出键盘再收起时,原虚拟键盘位点击
- iOS键盘动画细节
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。