Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
import 'package:flutter/material.dart';
class PinInput extends StatefulWidget {
PinInput(
{Key key,
this.numberOfBlock = 6,
this.controller,
this.validator,
this.decoration,
this.keyboardType,
this.style,
this.obscureText=false,
this.cursorColor,
this.enabled = true})
: super(key: key);
final bool obscureText;
final PinEdittingController controller;
final FormFieldValidator<String> validator;
final TextInputType keyboardType;
final int numberOfBlock;
final InputDecoration decoration;
final TextStyle style;
final Color cursorColor;
final bool enabled;
@override
State<StatefulWidget> createState() {
return _PinInputState();
}
}
class _PinInputState extends State<PinInput> {
List<FocusNode> _nodes;
List<TextEditingController> _controllers;
@override
void initState() {
_controllers =
List.generate(widget.numberOfBlock, (int) => TextEditingController());
_nodes = List.generate(widget.numberOfBlock, (int) => FocusNode());
super.initState();
}
@override
void dispose() {
_nodes.forEach((node) => node.dispose());
_controllers.forEach((node) => node.dispose());
super.dispose();
}
@override
Widget build(BuildContext context) {
List<Widget> children = [];
for (var i = 0; i < widget.numberOfBlock; i++) {
children.add(makeTextField(context, i));
}
return Container(
width: double.infinity,
child: Row(
children: children,
),
);
}
Widget makeTextField(BuildContext context, int index) {
if (widget.controller._controllers == null) {
widget.controller.init(_controllers);
}
TextEditingController controller = widget.controller?._controllers[index];
return Expanded(
flex: 1,
child: Container(
padding: EdgeInsets.only(right: 3, left: 3),
child: TextField(
enabled: widget.enabled,
autofocus: index == 0,
controller: controller,
focusNode: _nodes[index],
obscureText: widget.obscureText,
textAlign: TextAlign.center,
cursorColor: widget.cursorColor,
style: widget.style,
decoration:
widget.decoration.copyWith(hintText: "", counter: Container()),
keyboardType: widget.keyboardType,
textInputAction: index + 1 < widget.numberOfBlock
? TextInputAction.next
: TextInputAction.done,
onChanged: (value) {
if (value.isNotEmpty && index + 1 < widget.numberOfBlock)
FocusScope.of(context).requestFocus(_nodes[index + 1]);
else if (value.isEmpty && index - 1 >= 0)
FocusScope.of(context).requestFocus(_nodes[index - 1]);
},
),
),
);
}
}
class PinEdittingController extends TextEditingController {
List<TextEditingController> _controllers;
String prevText;
init(List<TextEditingController> controllers) {
_controllers = controllers;
int i = 0;
_controllers?.forEach((node) {
if (!node.hasListeners) {
int index = i;
node.addListener(() {
_resetValue(index);
notifyListeners();
});
}
i++;
});
}
_resetValue(int i) {
String text = this.text;
if (text == prevText) return;
prevText = text;
List<String> texts = text.split("");
for (; i < texts.length; i++) {
_controllers[i].value = _controllers[i].value.copyWith(
text: texts[i],
selection: TextSelection.fromPosition(TextPosition(offset: 1)),
);
}
for (; i < _controllers.length; i++) {
_controllers[i].value = _controllers[i].value.copyWith(text: "");
}
}
@override
void addListener(listener) {
super.addListener(listener);
}
@override
void dispose() {
_controllers.forEach((node) => node.dispose());
super.dispose();
}
@override
String get text {
String text = "";
_controllers
.forEach((TextEditingController controller) => text += controller.text);
return text;
}
@override
TextEditingValue get value => super.value;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.