简体   繁体   English

StatefulWidget - FLutter

[英]StatefulWidget - FLutter

I need to edit this code, in a way to define only one variable widget which can be able to change on every state to a different widget type.我需要编辑此代码,以仅定义一个变量小部件,该小部件可以在每个 state 上更改为不同的小部件类型。 I need to be able to make a dynamic form no matter what the question and its type is, the way i handle it is somehow complex and not efficient.无论问题及其类型是什么,我都需要能够制作动态表格,我处理它的方式有点复杂且效率不高。 so is there any idea on how to change the same variable for different widget on every setState()那么关于如何在每个 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++;
    });
  }

as @proversion said in the comments, you can check in the widget tree, if a condition returns true or false.正如@proversion 在评论中所说,如果条件返回真或假,您可以检查小部件树。

Before you enter the child you could check with an inline if-statement like so: questionType == 'dropdown'? (Widget for True): (Widget for False)在输入孩子之前,您可以使用内联 if 语句进行检查,如下所示: questionType == 'dropdown'? (Widget for True): (Widget for False) questionType == 'dropdown'? (Widget for True): (Widget for False)

Or if you have to do a complex check, I would do this in the build Method before the return of the widget and set a boolean value there, which represents your check result.或者,如果您必须进行复杂的检查,我会在小部件return之前在build Method 中执行此操作,并在那里设置一个 boolean 值,它代表您的检查结果。 Then you can use this value (example: isTrue ) in the widget tree like isTure? (Widget for True): (Widget for False)然后你可以像 isTure 一样在小部件树中使用这个值(例如: isTrueisTure? (Widget for True): (Widget for False) isTure? (Widget for True): (Widget for False) . isTure? (Widget for True): (Widget for False)

Here is a sample code, that should work.这是一个示例代码,应该可以工作。

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'),
    );
  }
}

UPDATE更新

acc.符合。 to your provided code, you may want to check the following.对于您提供的代码,您可能需要检查以下内容。 I created a separate class which will return the right widget for the question.我创建了一个单独的 class 它将返回问题的正确小部件。 Just pass the type and additional the dropDownList to the function.只需将type和附加的dropDownList传递给 function。

General I would suggest to store the questions and the corresponding answers in the same array, this would be a easy call of the function like getInputWidget(type:question[i].type, dropDownList:question[i].dropDownList) .一般我建议将问题和相应的答案存储在同一个数组中,这将是 function 的简单调用,例如getInputWidget(type:question[i].type, dropDownList:question[i].dropDownList)

在此处输入图像描述

Source Code for above example上述示例的源代码

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]}'),
                    );
                  }),
            ),
          ],
        ),
      ),
    );
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM