StatefulWidget - FLutter

StatefulWidget - FLutter

我需要编辑此代码,以仅定义一个可变小部件的方式,该小部件可以在每种状态下更改为不同的小部件类型。 无论问题及其类型是什么,我都需要能够制作动态表格,我处理它的方式在某种程度上是复杂且效率低下的。 那么有没有关于如何在每个 setState()

上为不同的小部件更改相同变量的想法?
    `Column(
                  children: <Widget>[
                    questionText,
                    textCounter > 0 ? textField : SizedBox(),
                    selectCounter > 0 ? selectField : SizedBox()
                  ],
                )),`FutureBuilder(
              future: fetchQuestions(),
              builder: (context, snapshot) {
                if (snapshot.hasData) {
                  for (var i = 0; i < snapshot.data.length; i++) {
                    var temp = snapshot.data[i]['question_value'].toString();
                    var type = snapshot.data[i]['question_type'].toString();
                    questionsList.add(temp);
                    typeList.add(type);
                  }

                  return Align(
                    alignment: Alignment.bottomRight,
                    child: RaisedButton(
                      onPressed: () {
                        changeQuest(questionsList, typeList,
                            snapshot.data.length, snapshot.data);
                      },
                      child: Text('next'),
                    ),
                  );
                } else
                  return Center(child: CircularProgressIndicator());
              },
            ),

    changeQuest(List questions, List type, length, data) {
    setState(() {
      textCounter = 0;
      selectCounter = 0;
      integerCounter = 0;
      if (counter < length) {
        questionText = Text(questions[counter]);
        if (type[counter] == 'Integer') {
          textCounter++;
          textField = TextFormField(
            decoration: new InputDecoration(labelText: "Enter your number"),
            keyboardType: TextInputType.number,
            inputFormatters: <TextInputFormatter>[
              WhitelistingTextInputFormatter.digitsOnly
            ], // Only numbers can be entered
          );
        } else if (type[counter] == 'Text') {
          textCounter++;
          textField = TextFormField(
            decoration: new InputDecoration(labelText: "Enter a text"),
            keyboardType: TextInputType.text,
          );
        } else if (type[counter] == 'Select') {
          selectCounter++;
          for (var i = 0; i < data[counter]['answers'].length; i++) {
            answersList
                .add(data[counter]['answers'][i]['answer_value'].toString());
          }
          dropDownValue = answersList[0];
          selectField = DropdownButton<String>(
            value: dropDownValue,
            icon: Icon(Icons.arrow_downward),
            iconSize: 24,
            elevation: 16,
            style: TextStyle(color: Colors.deepPurple),
            underline: Container(
              height: 2,
              color: Colors.deepPurpleAccent,
            ),
            onChanged: (value) {
              setState(() {
               dropDownValue = value;
              });
            },
            items: answersList
                .map<DropdownMenuItem<String>>((String value) {
              return DropdownMenuItem<String>(
                value: value,
                child: Text(value),
              );
            }).toList(),
          );
          print (dropDownValue);
        }
      }

      counter++;
    });
  }

正如@proversion 在评论中所说,如果条件 return 为真或假,您可以检查小部件树。

在输入 child 之前,您可以使用内联 if-statement 进行检查,如下所示: questionType == 'dropdown' ? (Widget for True) : (Widget for False)

或者如果你必须做一个复杂的检查,我会在小部件的 return 之前的 build 方法中执行此操作,并在那里设置一个布尔值,它代表你的检查结果。 然后你可以在小部件树中使用这个值(例如:isTrue),如 isTure ? (Widget for True) : (Widget for False).

这是一个示例代码,应该可以使用。

import 'package:flutter/material.dart';

class WidgetWithDifferentChildren extends StatefulWidget {
  @override
  _WidgetWithDifferentChildrenState createState() =>
      _WidgetWithDifferentChildrenState();
}

class _WidgetWithDifferentChildrenState
    extends State<WidgetWithDifferentChildren> {
  String questionType = '';
  String dropdownValue = 'SelectItem';
  String textValue = '';
  TextEditingController txtCtrl = TextEditingController();

  @override
  void dispose() {
    // TODO: implement dispose when using TextEditingController
    txtCtrl.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      child: questionType == ''
          ? Text('no Question Type')
          : questionType == 'dropdown'
              ? DropdownButton<String>(
                  value: dropdownValue,
                  onChanged: (String newValue) {
                    // Do something with the new Value
                    print('New DropDown value = $newValue');
                    setState(() {
                      dropdownValue = newValue;
                    });
                  },
                  items: <String>[
                    'SelectItem',
                    'Item 1',
                    'Item 2',
                    'Item 3',
                  ].map<DropdownMenuItem<String>>((String value) {
                    return DropdownMenuItem<String>(
                      value: value,
                      child: new Text(value),
                    );
                  }).toList(),
                )
              : questionType == 'textfield'
                  ? TextFormField(
                      controller: txtCtrl,
                      onChanged: (value) {
                        // Do something with the new Value
                        print('New TextField value = $value');
                        setState(() {
                          textValue = value;
                        });
                      },
                    )
                  : Text('Question Type does not match'),
    );
  }
}

更新

符合。对于您提供的代码,您可能需要检查以下内容。我创建了一个单独的 class,它将 return 问题的正确小部件。只需将 type 和附加的 dropDownList 传递给函数即可。

一般我建议将问题和相应的答案存储在同一个数组中,这将是像 getInputWidget(type:question[i].type, dropDownList:question[i].dropDownList).

这样的函数的简单调用

上面例子的源代码

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

class WidgetWithDifferentChildren extends StatefulWidget {
  @override
  _WidgetWithDifferentChildrenState createState() =>
      _WidgetWithDifferentChildrenState();
}

class _WidgetWithDifferentChildrenState
    extends State<WidgetWithDifferentChildren> {
  String questionType = '';
  String inputValue = '';
  List<String> answers = [];
  int questionID = 0;
  TextEditingController txtCtrl = TextEditingController();

  List<Map<String, String>> questionList = [
    {'question_value': 'text question ', 'question_type': 'text'},
    {'question_value': 'number question ', 'question_type': 'number'},
    {'question_value': 'select question ', 'question_type': 'select'},
    {'question_value': 'last question ', 'question_type': 'text'},
  ];
  List<String> dropDownList = [
    'Select an Item',
    'Answer A',
    'Answer B',
    'Answer C',
  ];

  @override
  void dispose() {
    // TODO: implement dispose when using TextEditingController
    txtCtrl.dispose();
    super.dispose();
  }

  Widget getInputWidget({@required String type, List<String> dropDownList}) {
    Widget inputW;
    if (type == 'number' || type == 'text') {
      inputW = TextFormField(
        controller: txtCtrl,
        decoration: new InputDecoration(labelText: "Enter a $type"),
        keyboardType:
            type == 'text' ? TextInputType.text : TextInputType.number,
        inputFormatters: <TextInputFormatter>[
          type == 'text'
              ? LengthLimitingTextInputFormatter(50)
              : WhitelistingTextInputFormatter.digitsOnly
        ], // Only numbers can be entered
        onChanged: (value) {
          setState(() {
            inputValue = value;
          });
        },
      );
    } else if (type == 'select') {
      if (inputValue.length == 0) {
        // set the input Value for the first time
        inputValue = dropDownList[0];
      }
      inputW = DropdownButton<String>(
        value: inputValue,
        icon: Icon(Icons.arrow_downward),
        iconSize: 24,
        elevation: 16,
        style: TextStyle(color: Colors.deepPurple),
        underline: Container(
          height: 2,
          color: Colors.deepPurpleAccent,
        ),
        onChanged: (value) {
          setState(() {
            inputValue = value;
          });
        },
        items: dropDownList.map<DropdownMenuItem<String>>((String value) {
          return DropdownMenuItem<String>(
            value: value,
            child: Text(value),
          );
        }).toList(),
      );
    }

    return inputW;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Padding(
        padding: const EdgeInsets.symmetric(vertical: 30, horizontal: 30),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            RaisedButton(
              onPressed: () {
                setState(() {
                  answers.add(inputValue);
                  inputValue = '';
                  txtCtrl.clear();
                  questionID = questionID + 1;
                });

                // unfocus to close the Keyboard
                // conrtibution to: https://flutterigniter.com/dismiss-keyboard-form-lose-focus/
                FocusScopeNode currentFocus = FocusScope.of(context);
                if (!currentFocus.hasPrimaryFocus) {
                  currentFocus.unfocus();
                }
              },
              child: Text('next'),
            ),
            getInputWidget(
                type: questionList[questionID]['question_type'],
                dropDownList: dropDownList),
            Divider(thickness: 2),
            Text('You enter: $inputValue'),
            Divider(thickness: 2),
            Text('Your answers are:'),
            Flexible(
              child: ListView.builder(
                  itemCount: answers.length,
                  itemBuilder: (context, index) {
                    return ListTile(
                      title: Text('$index. ${answers[index]}'),
                    );
                  }),
            ),
          ],
        ),
      ),
    );
  }
}