Flutter setState触发build重复调用随机字符生成函数,initState无效怎么解决?
问题修复方案
根因说明
- 所有可变状态、随机生成逻辑都写在
build方法内,每次点击按钮调用setState都会触发页面重绘,build方法会重新执行一遍,导致随机字符重新生成、用户选择的内容也被清空。 - 无需手动给State构造函数传递参数,State实例可直接通过
widget.属性名访问父组件PuzzlePage的所有属性,手动传参反而容易出现数据不同步的问题。
修改方法
- 将需要持久保存的变量提升为
_PuzzlePageState的成员变量 - 把随机字符生成、键盘参数计算的逻辑全部迁移到
initState中,该方法只会在页面初始化时执行一次,不会随重绘重复调用
完整修改后代码
import 'package:flutter/material.dart'; import 'dart:math'; class PuzzlePage extends StatefulWidget { final int? id; final String? image1; final String? image2; final String? puzzleAnswer; const PuzzlePage(this.id, this.image1, this.image2, this.puzzleAnswer, {super.key}); @override State<StatefulWidget> createState() => _PuzzlePageState(); } class _PuzzlePageState extends State<PuzzlePage> { late int extraSize; late int keyboardSize; late String randomCharactersString; late String keyboardWords; late List selection; @override void initState(){ super.initState(); // 所有初始化逻辑移到这里,仅执行一次 int remainingLetters = 26 - (widget.puzzleAnswer!.length); extraSize = (remainingLetters/2).ceil(); keyboardSize = widget.puzzleAnswer!.length + extraSize; randomCharactersString = RandomString(extraSize, widget.puzzleAnswer!); keyboardWords = randomCharactersString + widget.puzzleAnswer!; selection = []; } @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar( title:const Text("猜答案"), centerTitle: true, automaticallyImplyLeading: true, leading: IconButton(icon:const Icon(Icons.arrow_back), onPressed: () { Navigator.pop(context); }, ), ), body: Container( color: Colors.white54, child: Column( children: [ const SizedBox( height: 60, ), Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Container( height: 125, width: 125, child: Image(image: AssetImage("assets/images/${widget.image1}"))), const SizedBox( width: 20, ), Text(randomCharactersString), Container( height: 125, width: 125, child: Image(image: AssetImage("assets/images/${widget.image2}"))), ], ), Column( children: [ Container( height: 250, padding: const EdgeInsets.all(10), alignment: Alignment.center, child: GridView.builder(gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 7, crossAxisSpacing: 4, mainAxisSpacing: 4, ), itemCount: widget.puzzleAnswer!.length, shrinkWrap: true, itemBuilder: (context , index) { return ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: Colors.purple, textStyle: const TextStyle( fontSize: 20, fontWeight: FontWeight.bold ), ), onPressed: null, child: const Text("d"), ); } ) ), ], ), Expanded(child: Container( padding: const EdgeInsets.all(10), alignment: Alignment.center, child: GridView.builder(gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( childAspectRatio: 1, crossAxisCount: 7, crossAxisSpacing: 4, mainAxisSpacing: 4, ), itemCount: keyboardSize, itemBuilder: (context , index) { return InkWell( onTap:(){ setState((){ if(selection.contains(keyboardWords[index])) { selection.remove(keyboardWords[index]); } else { selection.add(keyboardWords[index]); } }); }, child: Container( padding:const EdgeInsets.all(10), alignment:Alignment.center, decoration:BoxDecoration( borderRadius:BorderRadius.circular(7) ), child:Text(keyboardWords[index], style:const TextStyle(color:Colors.black) ), ), ); } ) ), ), ], ), ), ), ); } } String RandomString(int strlen,String puzzleAnswer){ Random rnd = Random(); String result = ""; const chars = "abcdefghijklmnopqrstuvwxyz"; for (var i = 0; i < strlen; i++) { result += chars[rnd.nextInt(chars.length)]; } return result; }
额外优化建议
- 可修改
RandomString函数逻辑,过滤掉已经存在于答案中的字符,避免生成重复字符影响游戏体验 - 可将生成后的
keyboardWords随机打乱顺序,避免答案字符连续排列降低游戏难度
内容的提问来源于stack exchange,提问作者Dilpreet
相关产品推荐
相关产品推荐

