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

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

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&lt;SetPinScreen&gt; {
bool obscureText = true;
TextEditingController _otpTextController = TextEditingController();
bool isPinSet = false;
String pin = &#39;&#39;, confirmedPin = &#39;&#39;;
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(&quot;Floating action button pressed&quot;);
}
},
child: Padding(
padding: const EdgeInsets.all(15.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Align(
alignment: Alignment.centerLeft,
child: Text(
isPinSet
? &#39;Re-enter your PIN code to Confirm&#39;
: &#39;Set PIN for your Card Ending With XXXX&#39;,
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(
&#39;Pin must be at least 4 digits. It must not be single digits like&#39;
&#39; 1111 or digits in numerical order such as 1234&#39;,
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 ?? &#39;&#39;;
else
confirmedPin = val ?? &#39;&#39;;
if (pin.length == 4 &amp;&amp; !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>

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:

确定