Flutter错误:在构建期间调用了setState()或markNeedsBuild()。

huangapple go评论139阅读模式
英文:

Flutter error setState() or markNeedsBuild() called during build

问题

我想使用sms_autofill来在PinFieldAutoFill中设置PIN。

我面临两个问题

1- 在构建期间调用了setState()或markNeedsBuild()。

2- 每个子项必须被布局一次。

请告诉我如何解决这些问题。

这是我的代码:

  1. class _SetPinScreenState extends State<SetPinScreen> {
  2. bool obscureText = true;
  3. TextEditingController _otpTextController = TextEditingController();
  4. bool isPinSet = false;
  5. String pin = '', confirmedPin = '';
  6. void _updatePin(String val) {
  7. if (pin.length != 4)
  8. pin = val;
  9. else
  10. confirmedPin = val;
  11. if (pin.length == 4) {
  12. setState(() {
  13. isPinSet = true;
  14. });
  15. }
  16. }
  17. @override
  18. void dispose() {
  19. _otpTextController.dispose();
  20. super.dispose();
  21. }
  22. @override
  23. Widget build(BuildContext context) {
  24. bool isButtonEnabled = (pin == confirmedPin);
  25. return MainTemplate(
  26. isFloatingButtonVisible: true,
  27. isFloatingActionButtonDisabled: isButtonEnabled,
  28. floatingButtonAction: () {
  29. if (isButtonEnabled) {
  30. print("Floating action button pressed");
  31. }
  32. },
  33. child: Padding(
  34. padding: const EdgeInsets.all(15.0),
  35. child: Column(
  36. crossAxisAlignment: CrossAxisAlignment.start,
  37. children: [
  38. Align(
  39. alignment: Alignment.centerLeft,
  40. child: Text(
  41. isPinSet
  42. ? 'Re-enter your PIN code to Confirm'
  43. : 'Set PIN for your Card Ending With XXXX',
  44. style: TextStyle(fontWeight: FontWeight.w700, fontSize: 30),
  45. ),
  46. ),
  47. SizedBox(height: 20),
  48. Center(
  49. child: PinFieldAutoFill(
  50. decoration: UnderlineDecoration(
  51. textStyle: Theme.of(context).textTheme.subtitle1.copyWith(
  52. fontWeight: FontWeight.bold,
  53. fontSize: 15,
  54. ),
  55. gapSpace: 8,
  56. obscureStyle: ObscureStyle(isTextObscure: obscureText),
  57. lineHeight: 1.2,
  58. colorBuilder:
  59. PinListenColorBuilder(Colors.black, Colors.grey.shade400),
  60. ),
  61. onCodeChanged: _updatePin,
  62. codeLength: 4,
  63. autoFocus: true,
  64. controller: _otpTextController,
  65. keyboardType: TextInputType.number,
  66. ),
  67. ),
  68. SizedBox(height: 20),
  69. Text(
  70. 'Pin must be at least 4 digits. It must not be single digits like 1111 or digits in numerical order such as 1234',
  71. style: TextStyle(
  72. color: Colors.black,
  73. ),
  74. ),
  75. ],
  76. ),
  77. ),
  78. );
  79. }
  80. }
英文:

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

  1. class _SetPinScreenState extends State&lt;SetPinScreen&gt; {
  2. bool obscureText = true;
  3. TextEditingController _otpTextController = TextEditingController();
  4. bool isPinSet = false;
  5. String pin = &#39;&#39;, confirmedPin = &#39;&#39;;
  6. void _updatePin(String val) {
  7. if (pin.length != 4)
  8. pin = val;
  9. else
  10. confirmedPin = val;
  11. if (pin.length == 4) {
  12. setState(() {
  13. isPinSet = true;
  14. });
  15. }
  16. }
  17. @override
  18. void dispose() {
  19. _otpTextController.dispose();
  20. super.dispose();
  21. }
  22. @override
  23. Widget build(BuildContext context) {
  24. bool isButtonEnabled = (pin == confirmedPin);
  25. return MainTemplate(
  26. isFloatingButtonVisible: true,
  27. isFloatingActionButtonDisabled: isButtonEnabled,
  28. floatingButtonAction: () {
  29. if (isButtonEnabled) {
  30. print(&quot;Floating action button pressed&quot;);
  31. }
  32. },
  33. child: Padding(
  34. padding: const EdgeInsets.all(15.0),
  35. child: Column(
  36. crossAxisAlignment: CrossAxisAlignment.start,
  37. children: [
  38. Align(
  39. alignment: Alignment.centerLeft,
  40. child: Text(
  41. isPinSet
  42. ? &#39;Re-enter your PIN code to Confirm&#39;
  43. : &#39;Set PIN for your Card Ending With XXXX&#39;,
  44. style: TextStyle(fontWeight: FontWeight.w700, fontSize: 30),
  45. ),
  46. ),
  47. SizedBox(height: 20),
  48. Center(
  49. child: PinFieldAutoFill(
  50. decoration: UnderlineDecoration(
  51. textStyle: Theme.of(context).textTheme.subtitle1.copyWith(
  52. fontWeight: FontWeight.bold,
  53. fontSize: 15,
  54. ),
  55. gapSpace: 8,
  56. obscureStyle: ObscureStyle(isTextObscure: obscureText),
  57. lineHeight: 1.2,
  58. colorBuilder:
  59. PinListenColorBuilder(Colors.black, Colors.grey.shade400),
  60. ),
  61. onCodeChanged: _updatePin,
  62. codeLength: 4,
  63. autoFocus: true,
  64. controller: _otpTextController,
  65. keyboardType: TextInputType.number,
  66. ),
  67. ),
  68. SizedBox(height: 20),
  69. Text(
  70. &#39;Pin must be at least 4 digits. It must not be single digits like&#39;
  71. &#39; 1111 or digits in numerical order such as 1234&#39;,
  72. style: TextStyle(
  73. color: Colors.black,
  74. ),
  75. ),
  76. ],
  77. ),
  78. ),
  79. );
  80. }
  81. }

答案1

得分: 1

对于你的第一个问题,将你的setState代码添加到WidgetsBinding.instance.addPostFrameCallback块中,如下所示:

  1. void _updatePin(String val) {
  2. if (pin.length != 4)
  3. pin = val;
  4. else
  5. confirmedPin = val;
  6. if (pin.length == 4) {
  7. WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
  8. setState(() {
  9. isPinSet = true;
  10. });
  11. });
  12. }
  13. }

对于你的第二个问题,我只是找到了一个帖子,可能会有帮助。

更新

当我运行你的代码时,我终于发现了真正的问题,在重新输入模式中,每次输入数字时,PinFieldAutoFill将被重建。

  1. void _updatePin(String? val) {
  2. if (pin.length != 4)
  3. pin = val ?? '';
  4. else
  5. confirmedPin = val ?? '';
  6. if (pin.length == 4 && !isPinSet) {
  7. WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
  8. setState(() {
  9. isPinSet = true;
  10. });
  11. });
  12. }
  13. }
英文:

for your first issue, add your setState code into WidgetsBinding.instance.addPostFrameCallback block like below

  1. void _updatePin(String val) {
  2. if (pin.length != 4)
  3. pin = val;
  4. else
  5. confirmedPin = val;
  6. if (pin.length == 4) {
  7. WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
  8. setState(() {
  9. isPinSet = true;
  10. });
  11. })
  12. }
  13. }

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

  1. void _updatePin(String? val) {
  2. if (pin.length != 4)
  3. pin = val ?? &#39;&#39;;
  4. else
  5. confirmedPin = val ?? &#39;&#39;;
  6. if (pin.length == 4 &amp;&amp; !isPinSet) {
  7. WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
  8. setState(() {
  9. isPinSet = true;
  10. });
  11. });
  12. }
  13. }

答案2

得分: 0

尝试将以下代码放置在onInit()函数中:

  1. bool isButtonEnabled = (pin == confirmedPin);
英文:

Try placing

  1. bool isButtonEnabled = (pin == confirmedPin);

on onInit() function.

答案3

得分: 0

  1. 在调用 `setState({})` 方法之前,请检查小部件 `mounted`

if(mounted) {
setState(() {
isPinSet = true;
});
}

  1. <details>
  2. <summary>英文:</summary>
  3. Before call `setState({})` method check widget `mounted`

if(mounted) {
setState(() {
isPinSet = true;
});
}

  1. </details>

huangapple
  • 本文由 发表于 2023年8月10日 13:44:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/76872906.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定