/code_field

Widget providing input code field to insert pin, sms and other auth codes.

Primary LanguageDartMIT LicenseMIT

Widget providing input code field to insert pin, sms and other auth codes.
Also can be used for time/date or any highly formatted input.
And supports backspace keyboard button.

InputCodeControl handles all logic parts, input validation, holds current value and index pointer to next field.\

Standard InputCodeField is drawn with underline and can be customized with InputCodeDecoration. Supports enable/disable state, obscuring, sizing, coloring, etc..

final codeControl = InputCodeControl(inputRegex: '^[0-9]*$');

InputCodeField(
  control: codeControl,
  count: 6,
  inputType: TextInputType.number,
  decoration: InputCodeDecoration(
    focusColor: Colors.blueGrey,
  ),
),

Structure

For better visual control can be used itemBuilder to build custom Field Item.
To get char at given index use [] operator on InputCodeControl.
To check if item at given index is focused use InputCodeControl.isFocused(index) and InputCodeControl.hasFocus to check if whole Widget has focus.

InputCodeField(
  control: codeControl
  itemBuilder: (context, index) => CustomCodeItem(
    char: codeControl[index],
    focused: codeControl.isFocused(index),
    ),
);


class CustomCodeItem extends StatelessWidget {
  final String char;
  final bool fieldFocused;
  final bool itemFocused;

  const CustomCodeItem({
    Key key,
    this.char: '',
    this.fieldFocused: false,
    this.itemFocused: false,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      width: 42.0,
      height: 42.0,
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(6.0),
        color: fieldFocused ? (itemFocused ? Colors.grey : Colors.grey.withOpacity(0.5)) : Colors.grey.withOpacity(0.25),
        border: Border.all(color: itemFocused ? Colors.black : Colors.grey),
      ),
      child: Center(
        child: Text(
          char,
          style: Theme.of(context).primaryTextTheme.headline4,
        ),
      ),
    );
  }
}

Structure

For total visual control use builder to build whole input widget. InputCodeField and InputCodeControl still handles all input logic and keyboard actions.

InputCodeField(
  control: codeControl
  builder: (context) => CustomCodeField(
    control: codeControl,
    ),
);


class CustomCodeField extends StatelessWidget {
  final InputCodeControl control;

  const CustomCodeField({
    Key key,
    this.control,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final items = List<Widget>();

    for (int i = 0; i < control.count; i++) {
      if (i > 0 && i % 3 == 0) {
        items.add(Container(
          margin: EdgeInsets.symmetric(horizontal: 24.0),
          height: 32.0,
          width: 2.0,
          color: control.hasFocus ? Colors.green : Colors.blueGrey,
        ));

        items.add(Container(
          height: 42,
          width: 1.0,
          color: Colors.blueGrey,
        ));
      }

      items.add(Expanded(
        child: Container(
          height: 42.0,
          color: control.isFocused(i, true) ? Colors.greenAccent.withOpacity(0.25) : Colors.transparent,
          child: Center(
            child: Text(
              control[i],
              style: Theme.of(context).primaryTextTheme.headline4,
            ),
          ),
        ),
      ));

      if (i < control.count - 1) {
        items.add(Container(
          height: 42,
          width: 1.0,
          color: Colors.blueGrey,
        ));
      }
    }

    return ClipRRect(
      borderRadius: BorderRadius.circular(16.0),
      child: Container(
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(16.0),
          border: Border.all(color: control.hasFocus ? Colors.green : Colors.blueGrey),
        ),
        child: Row(
          children: items,
        ),
      ),
    );
  }
}

Structure

What's missing:

  • overriding/editing from middle
  • copy/paste toolbar