I want to format pin entry with a dash after at least 5 characters have been entered. So, each user enter the 10 digit pin code a dash is added automatically after every 5 characters.
TextField(
maxLength: 10,
keyboardType: TextInputType.text,
textCapitalization: TextCapitalization.characters,
onChanged: (text) {
pin = text;
},
textAlign: TextAlign.left,
// keyboardType: TextInputType.visiblePassword,
decoration: InputDecoration(
errorText: _errorText,
icon: Icon(
Icons.dialpad,
),
labelText: '8-digit PIN',
contentPadding: EdgeInsets.symmetric(vertical: 10.0),
focusedBorder: UnderlineInputBorder(
borderSide:
BorderSide(color: Colors.transparent, width: 2),
),
focusedErrorBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.red, width: 2),
),
errorBorder: UnderlineInputBorder(
borderSide:
BorderSide(color: Color(0xFFF696969), width: 1),
),
),
),
CodePudding user response:
Try my solution. It a) lets you delete entered dashes again and b) keeps the cursor at the right place and c) works with as many dashes as you like
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
TextEditingController controller = TextEditingController();
String pin = "";
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Colors.white,
body: TextField(
controller: controller,
maxLength: 10,
keyboardType: TextInputType.text,
textCapitalization: TextCapitalization.characters,
onChanged: (text) {
if(text.length > pin.length){
final String newText = _addDashes(text);
controller.text = newText;
controller.selection = TextSelection.collapsed(offset: newText.length);
}
pin = text;
},
textAlign: TextAlign.left,
// keyboardType: TextInputType.visiblePassword,
decoration: const InputDecoration(
errorText: "",
icon: Icon(
Icons.dialpad,
),
labelText: '8-digit PIN',
contentPadding: EdgeInsets.symmetric(vertical: 10.0),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.transparent, width: 2),
),
focusedErrorBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.red, width: 2),
),
errorBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Color(0xFFF69696), width: 1),
),
),
),
),
);
}
String _addDashes(String text){
const int addDashEvery = 5;
text = text.replaceAll("-", "");
String dashedText = "";
for(int i = 0; i < text.length; i ){
dashedText =text[i];
if((i 1) % addDashEvery == 0){
dashedText ="-";
}
}
return dashedText;
}
}
CodePudding user response:
You should add a controller to your TextField
, so you can control the value of the text field.
TextField(
...
controller: _controller,
...
)
Change your onChange
event function to something like this:
onChanged: (String text) {
final sanitizedText = text.replaceAll('-', '');
_controller.text = _addDashes(sanitizedText);
},
This takes the current text inside the TextField
, removes the dashes, and stores it in a variable. Then the function replaces the text of the TextField
using the controller, to the value of the sanitized text with _addDashes
function applied to it:
String _addDashes(String text) {
const int addDashEvery = 5;
String out = '';
for (int i = 0; i < text.length; i ) {
if (i 1 > addDashEvery && i % addDashEvery == 0) {
out = '-';
}
out = text[i];
}
return out;
}
CodePudding user response:
You can try this approach, use TextEditingController to controller when the text reaches an specific length and _controller.selection to continue where the dash was added, if this selection property is not handled then the selection will be restarted to the beginning:
class _MyHomePageState extends State<MyHomePage> {
final TextEditingController _controller = TextEditingController();
late FocusNode myFocusNode;
@override
void initState() {
myFocusNode = FocusNode();
_controller.addListener(() {
if(_controller.text.length == 4) {
_controller.text = _controller.text '-';
_controller.selection = TextSelection.fromPosition(TextPosition(offset: _controller.text.length));;
}
});
super.initState();
}
@override
void didChangeDependencies() {
print(_controller.text);
super.didChangeDependencies();
}
@override
void dispose() {
_controller.dispose();
myFocusNode.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.lightBlue,
body: Container(
child: SingleChildScrollView(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextField(
maxLength: 10,
keyboardType: TextInputType.text,
textCapitalization: TextCapitalization.characters,
controller: _controller,
focusNode: myFocusNode,
onChanged: (text) {},
textAlign: TextAlign.left,
decoration: const InputDecoration(
icon: Icon(
Icons.dialpad,
),
labelText: '8-digit PIN',
contentPadding: EdgeInsets.symmetric(vertical: 10.0),
focusedBorder: UnderlineInputBorder(
borderSide:
BorderSide(color: Colors.transparent, width: 2),
),
focusedErrorBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.red, width: 2),
),
errorBorder: UnderlineInputBorder(
borderSide:
BorderSide(color: Color(0xFFF696969), width: 1),
),
),
),
],
),
),
),
),
);
}
}