virtual_keypad v1.1.1
pub.dev GitHub

Numeric and PIN pads

A PIN pad is a custom layout, which means you decide exactly which keys exist and where.

Install#

flutter pub add virtual_keypad
import 'package:virtual_keypad/virtual_keypad.dart';

The quickest numeric pad#

If you only want digits, a number field already gets one with no layout work.

TextField(
  controller: controller,
  keyboardType: TextInputType.number,
)
// with VirtualKeypad(standalone: true) below it

A PIN pad you control#

For a lock screen, an OTP box or a checkout, describe the grid yourself. This is the same mechanism ATM and POS flows use.

final pinLayout = [
  [
    VirtualKey.character(text: '1'),
    VirtualKey.character(text: '2'),
    VirtualKey.character(text: '3'),
  ],
  [
    VirtualKey.character(text: '4'),
    VirtualKey.character(text: '5'),
    VirtualKey.character(text: '6'),
  ],
  [
    VirtualKey.character(text: '7'),
    VirtualKey.character(text: '8'),
    VirtualKey.character(text: '9'),
  ],
  [
    VirtualKey.action(action: KeyAction.backSpace),
    VirtualKey.character(text: '0'),
    VirtualKey.action(action: KeyAction.done, label: 'OK'),
  ],
];

VirtualKeypad(
  type: KeyboardType.custom,
  customLayout: pinLayout,
)

customLayout and type: KeyboardType.custom go together. Using one without the other asserts immediately in debug, so the mistake surfaces at once rather than as an empty keyboard.

Making it look like a pad, not a keyboard#

A PIN pad wants big keys and few of them, so theme it rather than accepting keyboard defaults.

VirtualKeypad(
  type: KeyboardType.custom,
  customLayout: pinLayout,
  height: 360,
  width: 320,
  theme: VirtualKeypadTheme.dark.copyWith(
    keyTextSize: 28,
    keyBorderRadius: 16,
    verticalGap: 10,
    horizontalGap: 10,
  ),
)

Confirming each digit#

On a payment terminal a mis-registered digit is expensive, and the screen is often the only feedback the user gets.

VirtualKeypad(
  type: KeyboardType.custom,
  customLayout: pinLayout,
  feedback: KeyFeedback.both,
)

Reading the value#

Scope mode gives you the digits without going through a text field, which suits a PIN display made of dots.

final pin = VirtualKeypadController();

pin.addListener(() {
  if (pin.text.length == 4) verify(pin.text);
});

Wider keys#

A key's flex sets how many columns it spans, so a zero key can span two while the rest span one.

[
  VirtualKey.character(text: '0', flex: 2),
  VirtualKey.action(action: KeyAction.backSpace),
]