0

目前面临条件逻辑和 PageView 小部件的问题。假设 PageView 将动态生成 3 个页面。在这 3 个页面中,将生成不同的小部件。其中一个小部件是一个按钮(称为“Next”),它是一个 PageController,但该小部件必须被一个按钮小部件替换,该按钮小部件应该提交(称为“提交”)整个表单(PageView 被包裹在表单)。

看起来很明显,只需编写条件逻辑,将PageView的当前页面与PageView的长度进行比较(PageView填充了List,因此很容易得到长度)。然后在满足正确条件时切换小部件:当当前页面等于3时,改变小部件。不幸的是,PageView 会在每一页上呈现“下一步”按钮。因此,只有当我到达最后一页然后再次单击“下一步”时,它才会变为“提交”。当用户进入最后一页时,它应该是“提交”。

const int TRIVIA_STARTING_TIME = 10;

class TriviaOneForm extends StatefulWidget {
  final UserRepository _userRepository;

  TriviaOneForm({Key key, @required UserRepository userRepository})
      : assert(userRepository != null),
        _userRepository = userRepository,
        super(key: key);

  State<TriviaOneForm> createState() => _TriviaOneFormState();
}

class _TriviaOneFormState extends State<TriviaOneForm> {
  final TextEditingController _answerController = TextEditingController();

  UserRepository get _userRepository => widget._userRepository;

  TriviaOneBloc _triviaOneBloc;
  PageController _pageController;

  Timer _timer;

  bool _isLoadingScreen;
  bool _isNextOrSubmitButton;
  int _start;
  int _indexOfCarouselItem;
  List<int> _selectedValList;

  List _triviaDataList;

  @override
  void initState() {
    super.initState();
    _isLoadingScreen = true;
    _getTriviaData();
    _pageController = PageController();
    _indexOfCarouselItem = 0;
    _isNextOrSubmitButton = true;
    _selectedValList = [0, 0, 0, 0, 0];
    _triviaDataList = [];
    _start = TRIVIA_STARTING_TIME;
    _triviaOneBloc = BlocProvider.of<TriviaOneBloc>(context);
    _answerController.addListener(_onAnswerChanged);
  }

  @override
  void dispose() {
    if (_timer != null) {
      _timer.cancel();
    }
    _pageController.dispose();
    super.dispose();
  }

  void startTimer() {
    const oneSec = const Duration(seconds: 1);
    _timer = new Timer.periodic(
      oneSec,
      (Timer timer) => setState(
        () {
          if (_start < 1) {
            timer.cancel();
          } else {
            _start = _start - 1;
          }
        },
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return BlocListener<TriviaOneBloc, TriviaOneState>(
      listener: (context, state) {
        if (state.isFailure) {
          Scaffold.of(context)
            ..hideCurrentSnackBar()
            ..showSnackBar(
              SnackBar(
                content: Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: <Widget>[
                    Text('Submition Failure'),
                    Icon(Icons.error)
                  ],
                ),
                backgroundColor: Colors.red,
              ),
            );
        }
        if (state.isSubmitting) {
          Scaffold.of(context)
            ..hideCurrentSnackBar()
            ..showSnackBar(
              SnackBar(
                content: Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: <Widget>[
                    Text('Submitting Answers...'),
                  ],
                ),
              ),
            );
        }
        if (state.isSuccess) {
          BlocProvider.of<TriviaOneBloc>(context).add(Submitted());
        }
      },
      child: BlocBuilder<TriviaOneBloc, TriviaOneState>(
        builder: (context, state) {
          return _isLoadingScreen
              ? _displayLoadScreen()
              : Padding(
                  padding: EdgeInsets.all(20.0),
                  child: Form(
                    child: PageView(
                      physics: NeverScrollableScrollPhysics(),
                      controller: _pageController,
                      reverse: false,
                      scrollDirection: Axis.horizontal,
                      children: _triviaDataList.map<Widget>((triviaData) {
                        return ListView(
                          shrinkWrap: true,
                          children: <Widget>[
                            Text(triviaData.getQuestion),
                            ListView(
                              shrinkWrap: true,
                              children: triviaData.getAnswers
                                  .map<Widget>((triviaAnswer) {
                                int index =
                                    triviaData.getAnswers.indexOf(triviaAnswer);
                                return ListTile(
                                  title: Text(triviaAnswer.getAnswer),
                                  leading: Radio(
                                    value: index,
                                    groupValue:
                                        _selectedValList[_indexOfCarouselItem],
                                    onChanged: (int value) {
                                      setState(() {
                                        print(value);
                                        _selectedValList[_indexOfCarouselItem] =
                                            value;
                                      });
                                    },
                                  ),
                                );
                              }).toList(),
                            ),
                            _isNextOrSubmitButton ? _nextButton() : _submitButton(),
                            RaisedButton(
                              onPressed: () {
                                startTimer();
                              },
                              child: Text('Start'),
                            ),
                            Text('$_start'),
                          ],
                        );
                      }).toList(),
                    ),
                  ),
                );
        },
      ),
    );
  }

  Widget _triviaControlButton(PageController pageController) {
    if (0 < _triviaDataList.length) {
      return RaisedButton(
        child: Text('Next'),
        onPressed: () {
          pageController.nextPage(
              duration: Duration(seconds: 1), curve: Curves.easeInOut);
          print('Next');
        },
      );
    } else if (pageController.page.toInt() == _triviaDataList.length) {
      return RaisedButton(
        child: Text('Submit'),
        onPressed: () {
          print('Submit');
        },
      );
    } else {
      return RaisedButton(
        child: Text('Error'),
        onPressed: () {
          print('Error');
        },
      );
    }
  }

  Widget _displayLoadScreen() {
    return Container(
      alignment: Alignment(0.0, 0.0),
      child: CircularProgressIndicator(),
    );
  }

  void _onAnswerChanged() {
    _triviaOneBloc.add(AnswerChanged(answer: _answerController.text));
  }

  void _getTriviaData() async {
    var data = _userRepository.retrieveTriviaData();
    // Await trivia data to be retrieved from firebase
    await data.getDocuments().then((collection) {
      collection.documents.forEach((document) {
        TriviaData triviaData = TriviaData();
        List<TriviaAnswer> triviaAnswerList = List<TriviaAnswer>();
        // Iterate through all of the answers for a question
        // Create a list of TriviaAnswer objects to hold key and value
        document.data['answers'].forEach((key, value) {
          TriviaAnswer triviaAnswer = TriviaAnswer();
          triviaAnswer.setAnswer = key;
          triviaAnswer.setAnswerValue = value;
          triviaAnswerList.add(triviaAnswer);
        });
        // Assign question String and answer List to TriviaData
        // Add all data to data list
        triviaData.setAnswers = triviaAnswerList;
        triviaData.setQuestion = document.data['question'];
        _triviaDataList.add(triviaData);
      });
    });
    setState(() {
      _isLoadingScreen = false;
    });
  }

  Widget _nextButton() {
    return RaisedButton(
      child: Text('Next'),
      onPressed: () {
        if (_indexOfCarouselItem < _triviaDataList.length) {
          _pageController.nextPage(
              duration: const Duration(milliseconds: 100),
              curve: Curves.easeInOut);
          setState(() {
            _start = TRIVIA_STARTING_TIME;
            _indexOfCarouselItem += 1;
          });
        }
        if (_indexOfCarouselItem == _triviaDataList.length) {
          Future.delayed(const Duration(seconds: 0), () {
            setState(() {
              _isNextOrSubmitButton = false;
            });
          });
        }
        try {
          if (_timer != null || !_timer.isActive) {
            startTimer();
          }
        } catch (_) {
          print('Error: Timer is already disabled');
        }
      },
    );
  }

  Widget _submitButton() {
    return RaisedButton(
      child: Text('Submit'),
      onPressed: () {
        print(_selectedValList);
        _userRepository.storeTriviaToFirebase();
        setState(() {
          if (_timer != null || _timer.isActive) {
            _timer.cancel();
          }
        });
      },
    );
  }
}

编辑 1:这是我用于在 PageView 中填充按钮的更新代码。我将字符串设置为初始值“Next”,然后在 _indexOfCarouselItem + 2 == _triviaDataList.length 为真时更新它。满足条件时,更新的值将是“提交”。

Widget _triviaControlButton() {
    return RaisedButton(
      child: Text(buttonText),
      onPressed: () {
        _pageController.nextPage(
            duration: const Duration(milliseconds: 100),
            curve: Curves.easeInOut);
        if (_indexOfCarouselItem + 2 == _triviaDataList.length) {
          setState(() {
            buttonText = "Submit";
          });
        }
        if (_indexOfCarouselItem < _triviaDataList.length) {
          setState(() {
            _start = TRIVIA_STARTING_TIME;
            _indexOfCarouselItem += 1;
          });
        }
        print(_indexOfCarouselItem);
        print(_triviaDataList.length);
      },
    );
  }
4

1 回答 1

1

我现在正在打电话,所以我不能保证我发布的代码没问题,但你会明白的。

第一:我不认为你需要 2 个按钮,如果它们在大小等方面是相等的,所以你可以实现这样的东西:

child: Text( _indexOfCarouselItem += 1 !=  _triviaDataList.length
 ? 'Next' : 'Submit')

然后在 onPressed 中使用相同的逻辑:

onPressed() {
   _indexOfCarouselItem += 1 != _triviaDataList.length ? doSomethibg : doSomethingDifferent;
}

编辑:好的,如果我理解正确,现在的问题是由于转换按钮显示“提交”但还没有问题吗?如果是这种情况,您可以像您说的那样添加延迟,但我认为更好的方法是将按钮的文本与问题联系起来。我的意思是你可以保留实际的逻辑(因为它有效)并添加如下内容:

孩子:文本(_indexOfCarouselItem += 1!= _triviaDataList.length && questionText!=“” ?“下一步”:“提交”)

这个逻辑也可以应用在 if ... else ... 块中。

编辑2:试试这个:

Widget _triviaControlButton() {
    return RaisedButton(
      child: Text(buttonText),
      onPressed: () {
        _pageController.nextPage(
            duration: const Duration(milliseconds: 100),
            curve: Curves.easeInOut);
        if (_indexOfCarouselItem < _triviaDataList.length) {
          setState(() {
            _start = TRIVIA_STARTING_TIME;
            _indexOfCarouselItem += 1;
          });
if (_indexOfCarouselItem == _triviaDataList.length) {
          setState(() {
            buttonText = "Submit";
          });
        }
      },
    );
  }
于 2020-03-31T01:33:06.997 回答