Copyright notice: This article is the blogger’s original article, reproduced please indicate the source!

I just finished a financial project with Flutter, which uses a password input field similar to wechat and Alipay. Then I implemented my own custom keyboard for security. Today I share a wave with you

Results show

The effect is shown below:

The layout form, we can adjust according to their specific needs, I wrote here demo is such a layout, this adjustment is very simple (originally wanted to get GIF, but not…) .

Analysis of a wave

First, we need to customize the password input box. When we enter a password, the password input box will be filled with one digit. This process is actually drawn by ourselves:

  1. Start by drawing six password boxes
  2. Accept the password passed by the caller and draw the number of password boxes according to the length of the password

Input box implementation

Class CustomJPasswordField extends StatelessWidget {// pass in the current password String data; CustomJPasswordField(this.data); @override Widget build(BuildContext context) {returnCustomPaint( painter: MyCustom(data), ); Class MyCustom extends CustomPainter {/// The length of the password passed in to draw the dot StringpwdLength; MyCustom(this.pwdLength); @override void paint(Canvas Canvas, Size Size) {// Password brush paint mPwdPaint; Paint mRectPaint; // Initialize password Paint mPwdPaint = new Paint(); mPwdPaint.. color = Colors.black; // mPwdPaint.setAntiAlias(true); // Initialize the password box mRectPaint = new Paint(); mRectPaint.. color = Color(0xff707070); RRect r = new rrect. fromLTRBR(0.0, 0.0, sie.width, sie.height, new radio.height / 12); Mrectpaint. style = paintingstyle. stroke; canvas.drawRRect(r, mRectPaint); Var per = size.width / 6.0; var offsetX = per;whileWidth) {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; /// There are several passwords, draw some solid circlesfor(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 to 2 * PI,true, mPwdPaint);
    }
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return true; }}Copy the code

Custom keyboard

So that’s it, we’re done with our first key, the custom password input field, and then the second step is to implement the custom password keyboard. The password keyboard can also be completely customized to draw, but I’m using a simpler implementation, directly using multiple buttons to assemble a keyboard,

The keyboard is basically 12 buttons with the same style, but different text, so we can define a common button style, and then we can call back the click event to the caller’s definition,

import 'package:flutter/material.dart'; Class CustomKbBtn extends StatefulWidget {/// The text content displayed by the button is String text; CustomKbBtn({Key key, this.text, this.callback}) : super(key: key); /// Final callback for button click events; @override State<StatefulWidget>createState() {
    returnButtonState(); }} class ButtonState extends State<CustomKbBtn> {var backMethod; voidback() {
    widget.callback('$backMethod'); } @override Widget build(BuildContext context) {// get the total width of the current screen, MediaQueryData mediaQuery = mediaQuery.of (context); var _screenWidth = mediaQuery.size.width;returnNew Container(height:50.0, width: _screenWidth / 3, child: new OutlineButton(// Rectangle 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),), // Button pressed: back,); }}Copy the code

Custom keyboard code implementation

Once we have buttons, we assemble them into a full keyboard:

Class MyKeyboard extends StatefulWidget {final callback; MyKeyboard(this.callback); @override State<StatefulWidget>createState() {
    returnnew MyKeyboardStat(); } } class MyKeyboardStat extends State<MyKeyboard> { final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>(); /// define the button interface exposed to the caller /// callback function body var backMethod; voidonCommitChange() {
    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("Seven"));
  }

  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")); } /// click delete voidonDeleteChange() {
    widget.callback(new KeyEvent("del"));
  }

  @override
  Widget build(BuildContext context) {
    returnNew Container(key: _scaffoldKey, width: double. Infinity, height: 250.0, color: Colors. White, child: New Column(children: <Widget>[new Container(height:30.0, color: color.white, alignment: align.center, child: new Text('Slide hide', style: new TextStyle(fontSize: 12.0, color: color (0xFF999999)),),), <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:'delete', callback: (val) => onDeleteChange()),
                  CustomKbBtn(
                      text: '0', callback: (val) => onZeroChange(context)),
                  CustomKbBtn(text: 'sure', callback: (val) => onCommitChange()), ], ), ], ) ], ), ); }}Copy the code

The KeyEvent() class is called in KeyEvent(), which is called in KeyEvent()

Class KeyEvent {/// The value of the currently clicked button is String key; KeyEvent(this.key); bool isDelete() => this.key =="del";
  bool isCommit() => this.key == "commit";
}
Copy the code

The class actually takes the actual content of the button, and the caller can use the value of the key to determine whether the number button, delete button, or OK button is clicked to change the password.

Note that the password keyboard pops up from the bottom of the screen. Here I use the showBottomSheet of the Flutter. This is the official widget for the Flutter to pop up the keyboard.

Let’s just go to the code

Class main_keyboard extends StatefulWidget {static final String sName ="enter";

  @override
  State<StatefulWidget> createState() {
    returnnew keyboardState(); }} class keyboardState extends State<main_keyboard> {/// Password StringpwdData = ' '; /* GlobalKey: ScaffoldState: Scaffolds the scaffolds framework The value of _scaffoldKey is the only key for the ScaffoldState */ Final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>(); // VoidCallback: a callback with no arguments and no data returned VoidCallback _showBottomSheetCallback; @override voidinitState() {

    _showBottomSheetCallback = _showBottomSheet;
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      key: _scaffoldKey,
      body: _buildContent(context),
    );
  }

  Widget _buildContent(BuildContext c) {
    returnNew 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()'Please enter your new payment password here', style: new TextStyle(fontSize: 18.0, color: color (0xFF333333)),),), /// Const EdgeInsets. Only (top: 15.0), child: _buildPwd(pwdData), ), ], ), ); } /// Password keyboard confirmation button event voidonAffirmButtonVoid _onKeyDown(KeyEvent data){// If the delete button is clicked, the password will be changedif (data.isDelete()) {
      if (pwdData.length > 0) {
        pwdData = pwdData.substring(0, pwdData.length - 1);
        setState(() {}); }} // When the OK button is clickedelse if (data.isCommit()) {
      if (pwdData.length ! = 6) { // Fluttertoast.showToast(msg:"Password is less than 6 digits. Please try again.", gravity: ToastGravity.CENTER);
        return; } onAffirmButton(); } // Click the numeric button to complete the password concatenationelse {
      if (pwdData.length < 6) {
        pwdData += data.key;
      }
      setState(() {}); }} /// At the bottom of the pop-up custom keyboard slide disappear void_showBottomSheet() {
    setState(() {
      // disableThe button _showBottomSheetCallback = null; }); ShowBottomSheet showBottomSheet showBottomSheet showBottomSheet showBottomSheet _scaffoldKey is the only key of the Scaffold state. Show scaffoldKey.currentState. showBottomSheet<void>((BuildContext context) {/// Pass the custom password keyboard as its child where the callback function is passedreturn new MyKeyboard(_onKeyDown);
    })
        .closed
        .whenComplete(() {
      if (mounted) {
        setState(() {// re-enable the button // re-enable the button _showBottomSheetCallback = _showBottomSheet; }); }}); } /// The build password input box defines its width and height Widget _buildPwd(var)pwd) {
    returnNew GestureDetector(Child: new Container(width: 250.0, height:40.0, // color: Colors. White, new GestureDetector(child: new Container(width: 250.0, height:40.0, // color: Colors. White, new GestureDetector(child: new Container(width: 250.0, height:40.0, // color: Colors. new CustomJPasswordField(pwdOnTap: () {_showBottomSheetCallback(); }); }}Copy the code

And we’re done, and now we have what we want. Remember I write blog, under the basic code is, the more I put the some instructions are written comments in the code, I think it is more intuitive, I hope you like this way, if this article helps to you, hope you can little love, give me a little encouragement, every time I see some reviews and ordered like, will be very happy, ha ha. A little attention would be nice.

If you have any questions, please feel free to contact me. We will see you next time!

Code to Github portal like it, trouble little star oh!

Welcome everyone to pay attention to the public account: the interviewer said that here will share the interview process in all aspects, including resume optimization, interview preparation, all kinds of interviews, experience sharing, and so on interesting things.