Создание виджетов в просмотре страницы на основе условной логики

В настоящее время возникает проблема с условной логикой и виджетом PageView. Допустим, PageView будет динамически генерировать 3 страницы. На этих трех страницах будут созданы разные виджеты. Один из виджетов - это кнопка (называемая "Далее"), которая является PageController, но этот виджет должен быть заменен виджетом кнопки, который должен отправить (называемый "Отправить") всю форму (PageView завернут в форма).

Это кажется очевидным, просто напишите условную логику, которая сравнивает текущую страницу PageView с длиной PageView (PageView заполняется списком, поэтому длину легко получить). Затем переключите виджеты, когда соблюдаются правильные условия: когда текущая страница равна 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. Я устанавливаю для String начальное значение "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);
      },
    );
  }

1 ответ

Я сейчас говорю по телефону, поэтому не могу гарантировать, что отправленный мной код в порядке, но вы поняли идею.

Во-первых: я не думаю, что вам нужны 2 кнопки, если они равны по размеру и т.д., поэтому вы можете реализовать что-то вроде этого:

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

А затем используйте ту же логику в onPressed:

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

Изменить: Хорошо, если я правильно понимаю, проблема в том, что из-за перехода на кнопке написано "Отправить", но еще нет вопросов? Если это так, как вы сказали, добавьте задержку, но я думаю, что лучше будет связать текст кнопки с вопросом. Я имею в виду, что вы можете сохранить фактическую логику (потому что она работает) и добавить что-то вроде этого:

child: Text (_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";
          });
        }
      },
    );
  }
Другие вопросы по тегам