Did any of you happen to encounter this bug before? I'm trying to implement OTP for my app project, but during the quick focus change between the 6 fields, Flutter apparently doesn't have enough time to recognize that the keyboards have TextInputType.number as keybord type.
This also happens on a physical device.
Here is an example video of the bug: https://drive.google.com/file/d/127dk7OyMpQazLF6b1nQfgIJHBEVXYAJN/view?usp=sharing
Code explanation:
I created 6 textformfields and gave them a initial value of the unicode \u200b (except textfield 1), in order to detect if a user pressed delete in an empty textfield.
Here is my code:
class enter_safecode extends StatefulWidget {
const enter_safecode({super.key});
@override
State<enter_safecode> createState() => _enter_safecodeState();
}
class _enter_safecodeState extends State<enter_safecode> {
final _Number1FormKey = GlobalKey<FormState>();
String? Number1ErrorText; // Variable zur Verfolgung des Fehlermeldungstextes
TextEditingController _Number1Controller =
TextEditingController();// Der kann den Zustand des Textfeldes kontrollieren und den eingegebenen Text aufrufen
final _Number2FormKey = GlobalKey<FormState>();
String? Number2ErrorText;
TextEditingController _Number2Controller =
TextEditingController();
final _Number3FormKey = GlobalKey<FormState>();
String? Number3ErrorText;
TextEditingController _Number3Controller =
TextEditingController();
final _Number4FormKey = GlobalKey<FormState>();
String? Number4ErrorText;
TextEditingController _Number4Controller =
TextEditingController();
final _Number5FormKey = GlobalKey<FormState>();
String? Number5ErrorText;
TextEditingController _Number5Controller =
TextEditingController();
final _Number6FormKey = GlobalKey<FormState>();
String? Number6ErrorText;
TextEditingController _Number6Controller =
TextEditingController();
ScrollPhysics CustomScrollPhysics() {
if (MediaQuery.of(context).viewInsets.bottom > 0) {
return BouncingScrollPhysics();
} else {
return NeverScrollableScrollPhysics();
}
}
@override
void initState() {
super.initState();
_Number2Controller = TextEditingController(text: '\u200b');
_Number3Controller = TextEditingController(text: '\u200b');
_Number4Controller = TextEditingController(text: '\u200b');
_Number5Controller = TextEditingController(text: '\u200b');
_Number6Controller = TextEditingController(text: '\u200b');
}
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
backgroundColor: Theme.of(context).primaryColor,
body: SingleChildScrollView(
physics: CustomScrollPhysics(),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.only(
left: 3.5 * globalWidthValue,
top: 23.15,
bottom: 33.85 * globalHeightValue),
child: IconButton(
onPressed: () {
if (MediaQuery.of(context).viewInsets.bottom > 0) {
FocusScope.of(context).unfocus();
Future.delayed(Duration(milliseconds: 200), () {});
} else {
Navigator.pop(context);
}
},
icon: SvgPicture.asset(
"assets/back_arrow.svg",
width: 11 * globalWidthValue,
height: 24 * globalHeightValue,
),
iconSize: 42 * globalWidthValue,
),
),
description(),
SizedBox(height: 29 * globalHeightValue),
Padding(
padding: EdgeInsets.symmetric( horizontal: 32.5 * globalWidthValue),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(
width: 50 * globalWidthValue,
child: Form(
key: _Number1FormKey,
child: TextFormField(
keyboardType: TextInputType.number,
enableInteractiveSelection: false,
maxLength: 1,
maxLines: null,
textAlign: TextAlign.center,
controller: _Number1Controller,
style: TextStyle(
color: Colors.black,fontWeight: FontWeight.w400, fontFamily: "Area", fontSize: calculateFontSize(40)
),
//Farbe vom eingegebenen Text
onChanged: (value)
{
if(_Number1Controller.text.length == 1)
{
FocusScope.of(context).nextFocus();
}
},
onTap: ()
{
if(_Number1Controller.text.length == 1)
{
FocusScope.of(context).nextFocus();
if(_Number2Controller.text.length == 2)
{
FocusScope.of(context).nextFocus();
if(_Number3Controller.text.length == 2)
{
FocusScope.of(context).nextFocus();
if(_Number4Controller.text.length == 2)
{
FocusScope.of(context).nextFocus();
if(_Number5Controller.text.length == 2)
{
FocusScope.of(context).nextFocus();
}
}
}
}
}
},
decoration: InputDecoration(
counter: Text(''),
contentPadding: EdgeInsets.only(top: 15 * globalHeightValue, bottom: 16 * globalHeightValue),
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
// Wenn das Feld nicht angeklickt ist
borderSide: BorderSide(color: Colors.white),
borderRadius: BorderRadius.all(Radius.circular(15)),
),
focusedBorder: OutlineInputBorder(
// Wenn das Feld angeklickt ist
borderSide:
BorderSide(color: Color(0xff40E0D0), width: 2),
borderRadius: BorderRadius.all(Radius.circular(15)),
),
),
),
),
),
SizedBox(
width: 50 * globalWidthValue,
child: Form(
key: _Number2FormKey,
child: TextFormField(
keyboardType: TextInputType.number,
enableInteractiveSelection: false,
maxLength: 2,
maxLines: null,
textAlign: TextAlign.center,
controller: _Number2Controller,
style: TextStyle(
color: Colors.black,fontWeight: FontWeight.w400, fontFamily: "Area", fontSize: calculateFontSize(40)
),
//Farbe vom eingegebenen Text
onChanged: (value)
{
if(value.length == 2)
{
FocusScope.of(context).nextFocus();
}
else if(value.length == 0)
{
FocusScope.of(context).previousFocus();
setState(() {
_Number2Controller = TextEditingController(text: '\u200b');
});
}
},
onTap: ()
{
if(_Number2Controller.text.length == 2)
{
FocusScope.of(context).nextFocus();
if(_Number3Controller.text.length == 2)
{
FocusScope.of(context).nextFocus();
if(_Number4Controller.text.length == 2)
{
FocusScope.of(context).nextFocus();
if(_Number5Controller.text.length == 2)
{
FocusScope.of(context).nextFocus();
}
}
}
}
else if(_Number1Controller.text.length == 0)
{
FocusScope.of(context).previousFocus();
}
},
decoration: InputDecoration(
counter: Text(''),
contentPadding: EdgeInsets.only(top: 15 * globalHeightValue, bottom: 16 * globalHeightValue),
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
// Wenn das Feld nicht angeklickt ist
borderSide: BorderSide(color: Colors.white),
borderRadius: BorderRadius.all(Radius.circular(15)),
),
focusedBorder: OutlineInputBorder(
// Wenn das Feld angeklickt ist
borderSide:
BorderSide(color: Color(0xff40E0D0), width: 2),
borderRadius: BorderRadius.all(Radius.circular(15)),
),
),
),
),
),
SizedBox(
width: 50 * globalWidthValue,
child: Form(
key: _Number3FormKey,
child: TextFormField(
keyboardType: TextInputType.number,
enableInteractiveSelection: false,
maxLength: 2,
maxLines: null,
textAlign: TextAlign.center,
controller: _Number3Controller,
style: TextStyle(
color: Colors.black,fontWeight: FontWeight.w400, fontFamily: "Area", fontSize: calculateFontSize(40)
),
//Farbe vom eingegebenen Text
onChanged: (value)
{
if(value.length == 2)
{
FocusScope.of(context).nextFocus();
}
else if(value.length == 0)
{
FocusScope.of(context).previousFocus();
setState(() {
_Number3Controller = TextEditingController(text: '\u200b');
});
}
},
onTap: ()
{
if(_Number3Controller.text.length == 2)
{
FocusScope.of(context).nextFocus();
if(_Number4Controller.text.length == 2)
{
FocusScope.of(context).nextFocus();
if(_Number5Controller.text.length == 2)
{
FocusScope.of(context).nextFocus();
}
}
}
else if(_Number3Controller.text.length == 1 && _Number2Controller.text.length == 1)
{
FocusScope.of(context).previousFocus();
if(_Number2Controller.text.length == 1 && _Number1Controller.text.length == 0)
{
FocusScope.of(context).previousFocus();
}
}
},
decoration: InputDecoration(
counter: Text(''),
contentPadding: EdgeInsets.only(top: 15 * globalHeightValue, bottom: 16 * globalHeightValue),
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
// Wenn das Feld nicht angeklickt ist
borderSide: BorderSide(color: Colors.white),
borderRadius: BorderRadius.all(Radius.circular(15)),
),
focusedBorder: OutlineInputBorder(
// Wenn das Feld angeklickt ist
borderSide:
BorderSide(color: Color(0xff40E0D0), width: 2),
borderRadius: BorderRadius.all(Radius.circular(15)),
),
),
),
),
),
SizedBox(
width: 50 * globalWidthValue,
child: Form(
key: _Number4FormKey,
child: TextFormField(
keyboardType: TextInputType.number,
enableInteractiveSelection: false,
maxLength: 2,
maxLines: null,
textAlign: TextAlign.center,
controller: _Number4Controller,
style: TextStyle(
color: Colors.black,fontWeight: FontWeight.w400, fontFamily: "Area", fontSize: calculateFontSize(40)
),
//Farbe vom eingegebenen Text
onChanged: (value)
{
if(value.length == 2)
{
FocusScope.of(context).nextFocus();
}
else if(value.length == 0)
{
FocusScope.of(context).previousFocus();
setState(() {
_Number4Controller = TextEditingController(text: '\u200b');
});
}
},
onTap: ()
{
if(_Number4Controller.text.length == 2)
{
FocusScope.of(context).nextFocus();
if(_Number5Controller.text.length == 2)
{
FocusScope.of(context).nextFocus();
}
}
else if(_Number4Controller.text.length == 1 && _Number3Controller.text.length == 1)
{
FocusScope.of(context).previousFocus();
if(_Number3Controller.text.length == 1 && _Number2Controller.text.length == 1)
{
FocusScope.of(context).previousFocus();
if(_Number2Controller.text.length == 1 && _Number1Controller.text.length == 0)
{
FocusScope.of(context).previousFocus();
}
}
}
},
decoration: InputDecoration(
counter: Text(''),
contentPadding: EdgeInsets.only(top: 15 * globalHeightValue, bottom: 16 * globalHeightValue),
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
// Wenn das Feld nicht angeklickt ist
borderSide: BorderSide(color: Colors.white),
borderRadius: BorderRadius.all(Radius.circular(15)),
),
focusedBorder: OutlineInputBorder(
// Wenn das Feld angeklickt ist
borderSide:
BorderSide(color: Color(0xff40E0D0), width: 2),
borderRadius: BorderRadius.all(Radius.circular(15)),
),
),
),
),
),
SizedBox(
width: 50 * globalWidthValue,
child: Form(
key: _Number5FormKey,
child: TextFormField(
keyboardType: TextInputType.number,
enableInteractiveSelection: false,
maxLength: 2,
maxLines: null,
textAlign: TextAlign.center,
controller: _Number5Controller,
style: TextStyle(
color: Colors.black,fontWeight: FontWeight.w400, fontFamily: "Area", fontSize: calculateFontSize(40)
),
//Farbe vom eingegebenen Text
onChanged: (value)
{
if(value.length == 2)
{
FocusScope.of(context).nextFocus();
}
else if(value.length == 0)
{
FocusScope.of(context).previousFocus();
setState(() {
_Number5Controller = TextEditingController(text: '\u200b');
});
}
},
onTap: ()
{
if(_Number5Controller.text.length == 2)
{
FocusScope.of(context).nextFocus();
}
else if(_Number5Controller.text.length == 1 && _Number4Controller.text.length == 1)
{
FocusScope.of(context).previousFocus();
if(_Number4Controller.text.length == 1 && _Number3Controller.text.length == 1)
{
FocusScope.of(context).previousFocus();
if(_Number3Controller.text.length == 1 && _Number2Controller.text.length == 1)
{
FocusScope.of(context).previousFocus();
if(_Number2Controller.text.length == 1 && _Number1Controller.text.length == 0)
{
FocusScope.of(context).previousFocus();
}
}
}
}
},
decoration: InputDecoration(
counter: Text(''),
contentPadding: EdgeInsets.only(top: 15 * globalHeightValue, bottom: 16 * globalHeightValue),
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
// Wenn das Feld nicht angeklickt ist
borderSide: BorderSide(color: Colors.white),
borderRadius: BorderRadius.all(Radius.circular(15)),
),
focusedBorder: OutlineInputBorder(
// Wenn das Feld angeklickt ist
borderSide:
BorderSide(color: Color(0xff40E0D0), width: 2),
borderRadius: BorderRadius.all(Radius.circular(15)),
),
),
),
),
),
SizedBox(
width: 50 * globalWidthValue,
child: Form(
key: _Number6FormKey,
child: TextFormField(
keyboardType: TextInputType.number,
enableInteractiveSelection: false,
maxLength: 2,
maxLines: null,
textAlign: TextAlign.center,
controller: _Number6Controller,
style: TextStyle(
color: Colors.black,fontWeight: FontWeight.w400, fontFamily: "Area", fontSize: calculateFontSize(40)
),
//Farbe vom eingegebenen Text
onFieldSubmitted: (value)
{
if(value.length == 1)
{
FocusScope.of(context).nextFocus();
}
},
onChanged: (value)
{
if(value.length == 0)
{
FocusScope.of(context).previousFocus();
setState(() {
_Number6Controller = TextEditingController(text: '\u200b');
});
}
},
onTap: ()
{
if(_Number6Controller.text.length == 1 && _Number5Controller.text.length == 1) //Text
{
FocusScope.of(context).previousFocus();
if(_Number5Controller.text.length == 1 && _Number4Controller.text.length == 1)
{
FocusScope.of(context).previousFocus();
if(_Number4Controller.text.length == 1 && _Number3Controller.text.length == 1)
{
FocusScope.of(context).previousFocus();
if(_Number3Controller.text.length == 1 && _Number2Controller.text.length == 1)
{
FocusScope.of(context).previousFocus();
if(_Number2Controller.text.length == 1 && _Number1Controller.text.length == 0)
{
FocusScope.of(context).previousFocus();
}
}
}
}
}
},
decoration: InputDecoration(
counter: Text(''),
contentPadding: EdgeInsets.only(top: 15 * globalHeightValue, bottom: 16 * globalHeightValue),
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
// Wenn das Feld nicht angeklickt ist
borderSide: BorderSide(color: Colors.white),
borderRadius: BorderRadius.all(Radius.circular(15)),
),
focusedBorder: OutlineInputBorder(
// Wenn das Feld angeklickt ist
borderSide:
BorderSide(color: Color(0xff40E0D0), width: 2),
borderRadius: BorderRadius.all(Radius.circular(15)),
),
),
),
),
),
],
),
),
],
),
),
),
);
}
}
class description extends StatelessWidget {
const description({super.key});
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.only(left: 19 * globalWidthValue),
child: Text(
"Schon da?",
style: TextStyle(
fontSize: calculateFontSize(30),
fontWeight: FontWeight.w600,
color: Colors.white),
),
),
Padding(
padding: EdgeInsets.only(left: 19.5 * globalWidthValue),
child: Text(
"Wir haben dir zur Bestätigung",
style: TextStyle(
fontSize: calculateFontSize(20),
fontWeight: FontWeight.w400,
color: Colors.white),
),
),
Padding(
padding: EdgeInsets.only(left: 19.5 * globalWidthValue),
child: Text(
"deiner E-Mail, eine Nachricht",
style: TextStyle(
fontSize: calculateFontSize(20),
fontWeight: FontWeight.w400,
color: Colors.white),
),
),
Padding(
padding: EdgeInsets.only(left: 19.5 * globalWidthValue),
child: Text(
"gesendet. Bitte gebe den 6-",
style: TextStyle(
fontSize: calculateFontSize(20),
fontWeight: FontWeight.w400,
color: Colors.white),
),
),
Padding(
padding: EdgeInsets.only(left: 19.5 * globalWidthValue),
child: Text(
"Stelligen Code unten ein.",
style: TextStyle(
fontSize: calculateFontSize(20),
fontWeight: FontWeight.w400,
color: Colors.white),
),
),
],
);
}
}
- I tried to use a delay before the focus change
- I updated Flutter to the newest Version