Héc*_*tor 1 state-management dart flutter flutter-getx
我正在学习在 Flutter 中使用 Getx 库,我遇到了以下问题:想法是有一个 TextFields 列表,其中每个 TextFields 都是可水平扩展的,也就是说,它在屏幕上占用的大小由键入的单词的大小,随着单词大小的增加,TextField 的大小也会增加。如果我添加一行,通过FloatingActionButton,没有问题,我可以顺利打字,但是当我添加第二行时,出现以下错误:
\n\n\n\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90 捕获异常通过小部件库 \xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\ x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\ xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\ x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\ x90\xe2\x95\x90\xe2\x95\x90\n构建 NewLineKeyword(dirty) 时抛出以下断言:\n在构建期间调用 setState() 或 markNeedsBuild()。
\n
\n\n此 GetX 小部件无法标记为需要构建,因为框架已经在构建小部件的过程中。仅当小部件的祖先之一当前正在构建时,才可以将其标记为需要在构建阶段构建。允许此异常,因为框架在子窗口之前构建父窗口小部件,这意味着将始终构建脏后代。否则,框架可能不会在此构建阶段访问此小部件。\n调用 setState() 或 markNeedsBuild() 的小部件是:GetX<NewLineKeywordController>
\n
\n\n控制器: null\ntag: null\nhas builder\nstate: GetXState#ae1d4(controller: Instance of \'NewLineKeywordController\')\n当进行有问题的调用时当前正在构建的小部件是: NewLineKeyword\ndirty\n相关错误-导致小部件是\nNewLineKeyword
\n
下图显示了运行时的情况:
\n\n下面是可水平扩展的 TextField 的代码:
\nclass NewLineKeyword extends GetView<NewLineKeywordController>{\n final Key myKey;\n\n const NewLineKeyword({ \n Key? key, \n required this.myKey, \n }) : super(key: key);\n\n @override\n Widget build(BuildContext context) {\n final newLineKeywordController = Get.put(NewLineKeywordController());\n newLineKeywordController.setNewLineSize(myKey, 60.0);\n\n return GetX<NewLineKeywordController>(\n builder: (_){\n return Row(\n children: <Widget>[\n const SizedBox(\n width: 7.5\n ),\n SizedBox(\n width: newLineKeywordController.getNewLineSize(myKey),\n child: TextField(\n autofocus: true,\n minLines: 1,\n maxLines: 1,\n decoration: const InputDecoration(\n constraints: BoxConstraints(minWidth: 15.0),\n border: InputBorder.none,\n contentPadding: EdgeInsets.only(bottom: 13.0),\n focusedBorder: UnderlineInputBorder(\n borderSide: BorderSide(color: Colors.blue)\n )\n ),\n style: const TextStyle(color: Colors.white, fontSize: 20.0),\n onChanged: (String newValue){\n // get the exact size of the String\n final TextPainter textPainter = TextPainter(\n text: TextSpan(text: newValue, style: const TextStyle(fontSize: 20.0)),\n textDirection: TextDirection.ltr,\n textScaleFactor: WidgetsBinding.instance.window.textScaleFactor,\n )..layout();\n\n newLineKeywordController.changeNewLineSize(myKey, textPainter.size.width + 2.0);\n },\n onSubmitted: (String newValue){\n // get the exact size of the String\n final TextPainter textPainter = TextPainter(\n text: TextSpan(text: newValue, style: const TextStyle(fontSize: 20.0)),\n textDirection: TextDirection.ltr,\n textScaleFactor: WidgetsBinding.instance.window.textScaleFactor,\n )..layout();\n\n newLineKeywordController.changeNewLineSize(myKey, textPainter.size.width + 2.0);\n }\n )\n )\n ]\n );\n }\n );\n }\n}\n
Run Code Online (Sandbox Code Playgroud)\n下面是 TextField Getx 控制器代码:
\nclass NewLineKeywordController extends GetxController{\n final RxMap<Key, double> _mapNewLineSize = <Key, double>{}.obs;\n\n void setNewLineSize(Key key, double size){\n _mapNewLineSize[key] = size;\n }\n\n void changeNewLineSize(Key key, double newSize){\n if(_mapNewLineSize[key] != null){\n _mapNewLineSize[key] = newSize;\n }\n }\n\n double getNewLineSize(Key key){\n if(_mapNewLineSize[key] != null){\n return _mapNewLineSize[key]!;\n }\n else{\n return 10.0;\n }\n }\n}\n
Run Code Online (Sandbox Code Playgroud)\n根据所需的关键字,关键字小部件创建所需的小部件(该小部件的控制器为空):
\nclass Keywords extends GetView<KeywordsController>{\n final String reservedKeyword;\n final Key mykey;\n\n const Keywords({\n Key? key, \n required this.reservedKeyword,\n required this.mykey\n }) : super(key: key);\n\n @override\n Widget build(BuildContext context){\n switch(reservedKeyword){\n case "newLine":\n return NewLineKeyword(myKey: mykey);\n //case "second option":\n //return ... \n //case "third option":\n //return ...\n default:\n return throw NullThrownError();\n }\n }\n}\n
Run Code Online (Sandbox Code Playgroud)\n下面的代码对应一行的Widget:
\nclass Line extends GetView<LineController> {\n final Key myKey;\n\n Line({Key? key, required this.myKey}) : super(key: key);\n\n @override\n final controller = Get.put(LineController());\n\n @override\n Widget build(BuildContext context) {\n return GestureDetector(\n child: GetX<LineController>(\n builder: (_){\n return Container(\n color: controller.getIsSelected(myKey) ? const Color(0x327a7a7a) : Colors.transparent,\n height: 35.0,\n child: Row(\n children: <Widget>[\n const SizedBox(width: 10.0),\n controller.getKeywords(myKey)\n ]\n )\n );\n }\n ),\n onLongPress: (){\n controller.changeIsSelected(myKey);\n }\n );\n }\n}\n
Run Code Online (Sandbox Code Playgroud)\nLine 小部件控制器的代码:
\nclass LineController extends GetxController{\n final RxMap<Key, Keywords> _mapKeywords = <Key, Keywords>{}.obs;\n\n void setKeywords(Key key, Keywords keyword){\n _mapKeywords[key] = keyword;\n }\n\n void changeKeywords(Key key, Keywords newKeyword){\n if(_mapKeywords[key] != null){\n _mapKeywords[key] = newKeyword;\n }\n }\n\n Keywords getKeywords(Key key){\n if(_mapKeywords[key] != null){\n return _mapKeywords[key]!;\n }\n else{\n return Keywords(reservedKeyword: "newLine", mykey: key);\n }\n }\n // set, get and change for isSelected\n}\n
Run Code Online (Sandbox Code Playgroud)\n下面的编辑器小部件是行列表所在的位置:
\nclass Editor extends GetView<EditorController> {\n const Editor({Key? key}) : super(key: key);\n\n @override\n Widget build(BuildContext context) {\n\n ScrollController scrollCode = ScrollController();\n\n final editorController = Get.put(EditorController());\n\n List<Line> lineList = editorController.getLineList();\n\n return Padding(\n padding: const EdgeInsets.fromLTRB(0.0, 0.0, 10.0, 120.0),\n child: GetX<EditorController>(\n builder: (_){\n return DraggableScrollbar.arrows(\n controller: scrollCode,\n child: ListView.builder(\n controller: scrollCode,\n itemCount: lineList.length,\n itemBuilder: (BuildContext context, int index){\n return lineList[index];\n }\n )\n );\n }\n )\n );\n }\n}\n
Run Code Online (Sandbox Code Playgroud)\n编辑Getx控制器:
\nclass EditorController extends GetxController{\n final RxList<Line> _codeList = <Line>[].obs;\n\n void addLine(Line value){\n _codeList.add(value);\n }\n\n List<Line> getLineList(){\n return _codeList;\n }\n\n}\n
Run Code Online (Sandbox Code Playgroud)\n下面是在编辑器中创建新行的按钮:
\nclass ExpandableFab extends StatelessWidget {\n\n const ExpandableFab({ Key? key }) : super(key: key);\n\n @override\n Widget build(BuildContext context) {\n final lineController = Get.put(LineController());\n final editorController = Get.put(EditorController());\n\n Key mykey;\n\n return FloatingActionButton(\n child: const Icon(\n Icons.add, \n ),\n onPressed: (){\n mykey = GlobalKey();\n lineController.setIsSelected(mykey, false);\n lineController.setKeywords(mykey, Keywords(reservedKeyword: "newLine", mykey: mykey));\n editorController.addLine(Line(myKey: mykey));\n }\n );\n }\n}\n
Run Code Online (Sandbox Code Playgroud)\n我不太理解这个错误,因为它们是同一小部件的不同实例,因此可以毫无问题地创建它。我真的迷失在这个问题中,在这种情况下如何创建多个小部件?
\n这是因为您正在尝试在构建小部件树时更新可观察值,这可能是由于该方法引起的newLineKeywordController.setNewLineSize(myKey, 60.0);
要解决这个问题,您可以将setNewLineSize
方法更改为:
void setNewLineSize(Key key, double size) async {
await Future.delayed(Duration.zero);
_mapNewLineSize[key] = size;
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
2618 次 |
最近记录: |