英文:
Flutter error setState() or markNeedsBuild() called during build
问题
我想使用sms_autofill来在PinFieldAutoFill
中设置PIN。
我面临两个问题:
1- 在构建期间调用了setState()或markNeedsBuild()。
2- 每个子项必须被布局一次。
请告诉我如何解决这些问题。
这是我的代码:
class _SetPinScreenState extends State<SetPinScreen> {
bool obscureText = true;
TextEditingController _otpTextController = TextEditingController();
bool isPinSet = false;
String pin = '', confirmedPin = '';
void _updatePin(String val) {
if (pin.length != 4)
pin = val;
else
confirmedPin = val;
if (pin.length == 4) {
setState(() {
isPinSet = true;
});
}
}
@override
void dispose() {
_otpTextController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
bool isButtonEnabled = (pin == confirmedPin);
return MainTemplate(
isFloatingButtonVisible: true,
isFloatingActionButtonDisabled: isButtonEnabled,
floatingButtonAction: () {
if (isButtonEnabled) {
print("Floating action button pressed");
}
},
child: Padding(
padding: const EdgeInsets.all(15.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Align(
alignment: Alignment.centerLeft,
child: Text(
isPinSet
? 'Re-enter your PIN code to Confirm'
: 'Set PIN for your Card Ending With XXXX',
style: TextStyle(fontWeight: FontWeight.w700, fontSize: 30),
),
),
SizedBox(height: 20),
Center(
child: PinFieldAutoFill(
decoration: UnderlineDecoration(
textStyle: Theme.of(context).textTheme.subtitle1.copyWith(
fontWeight: FontWeight.bold,
fontSize: 15,
),
gapSpace: 8,
obscureStyle: ObscureStyle(isTextObscure: obscureText),
lineHeight: 1.2,
colorBuilder:
PinListenColorBuilder(Colors.black, Colors.grey.shade400),
),
onCodeChanged: _updatePin,
codeLength: 4,
autoFocus: true,
controller: _otpTextController,
keyboardType: TextInputType.number,
),
),
SizedBox(height: 20),
Text(
'Pin must be at least 4 digits. It must not be single digits like 1111 or digits in numerical order such as 1234',
style: TextStyle(
color: Colors.black,
),
),
],
),
),
);
}
}
英文:
I want to set pin in PinFieldAutoFill
using sms_autofill
I am facing 2 issues
1- setState() or markNeedsBuild() called during build.
2- Each child must be laid out exactly once.
Kindly let me know how to solve that issues.
Here is my code
class _SetPinScreenState extends State<SetPinScreen> {
bool obscureText = true;
TextEditingController _otpTextController = TextEditingController();
bool isPinSet = false;
String pin = '', confirmedPin = '';
void _updatePin(String val) {
if (pin.length != 4)
pin = val;
else
confirmedPin = val;
if (pin.length == 4) {
setState(() {
isPinSet = true;
});
}
}
@override
void dispose() {
_otpTextController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
bool isButtonEnabled = (pin == confirmedPin);
return MainTemplate(
isFloatingButtonVisible: true,
isFloatingActionButtonDisabled: isButtonEnabled,
floatingButtonAction: () {
if (isButtonEnabled) {
print("Floating action button pressed");
}
},
child: Padding(
padding: const EdgeInsets.all(15.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Align(
alignment: Alignment.centerLeft,
child: Text(
isPinSet
? 'Re-enter your PIN code to Confirm'
: 'Set PIN for your Card Ending With XXXX',
style: TextStyle(fontWeight: FontWeight.w700, fontSize: 30),
),
),
SizedBox(height: 20),
Center(
child: PinFieldAutoFill(
decoration: UnderlineDecoration(
textStyle: Theme.of(context).textTheme.subtitle1.copyWith(
fontWeight: FontWeight.bold,
fontSize: 15,
),
gapSpace: 8,
obscureStyle: ObscureStyle(isTextObscure: obscureText),
lineHeight: 1.2,
colorBuilder:
PinListenColorBuilder(Colors.black, Colors.grey.shade400),
),
onCodeChanged: _updatePin,
codeLength: 4,
autoFocus: true,
controller: _otpTextController,
keyboardType: TextInputType.number,
),
),
SizedBox(height: 20),
Text(
'Pin must be at least 4 digits. It must not be single digits like'
' 1111 or digits in numerical order such as 1234',
style: TextStyle(
color: Colors.black,
),
),
],
),
),
);
}
}
答案1
得分: 1
对于你的第一个问题,将你的setState
代码添加到WidgetsBinding.instance.addPostFrameCallback
块中,如下所示:
void _updatePin(String val) {
if (pin.length != 4)
pin = val;
else
confirmedPin = val;
if (pin.length == 4) {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
setState(() {
isPinSet = true;
});
});
}
}
对于你的第二个问题,我只是找到了一个帖子,可能会有帮助。
更新
当我运行你的代码时,我终于发现了真正的问题,在重新输入模式中,每次输入数字时,PinFieldAutoFill
将被重建。
void _updatePin(String? val) {
if (pin.length != 4)
pin = val ?? '';
else
confirmedPin = val ?? '';
if (pin.length == 4 && !isPinSet) {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
setState(() {
isPinSet = true;
});
});
}
}
英文:
for your first issue, add your setState
code into WidgetsBinding.instance.addPostFrameCallback
block like below
void _updatePin(String val) {
if (pin.length != 4)
pin = val;
else
confirmedPin = val;
if (pin.length == 4) {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
setState(() {
isPinSet = true;
});
})
}
}
and for your second issue, i just found a post, might be helpful
Update
when i run your code, i finally found what the real issue is, in re-enter mod, the PinFieldAutoFill
will be rebuilt every time you typed a number
void _updatePin(String? val) {
if (pin.length != 4)
pin = val ?? '';
else
confirmedPin = val ?? '';
if (pin.length == 4 && !isPinSet) {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
setState(() {
isPinSet = true;
});
});
}
}
答案2
得分: 0
尝试将以下代码放置在onInit()函数中:
bool isButtonEnabled = (pin == confirmedPin);
英文:
Try placing
bool isButtonEnabled = (pin == confirmedPin);
on onInit() function.
答案3
得分: 0
在调用 `setState({})` 方法之前,请检查小部件 `mounted`
if(mounted) {
setState(() {
isPinSet = true;
});
}
<details>
<summary>英文:</summary>
Before call `setState({})` method check widget `mounted`
if(mounted) {
setState(() {
isPinSet = true;
});
}
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论