Flutter - 如何动态 PageView?

时间:2021-01-16 21:44:18

标签: flutter

我想创建一个调查。

在本次调查中,每个问题都将显示在一页上。 根据每个问题的答案,下一步可能会向用户提出不同的问题。

例如;第一个问题,也就是在第一页,有一个有两个选项的问题。如果用户选择第一个答案,则会在其前面出现一个新页面。如果他选择第二个答案,应该会出现一个不同的页面。

由于问题页面中会有下拉菜单、单选按钮等项目,所以有些情况下我需要设置状态。我在 UI 渲染期间在 initstate 中创建的项目没有更新。

在这些问题页面之间切换时还需要侧滑动画。

我应该如何使用哪种结构?我可以在 PageView 之外使用更符合逻辑的结构吗?

当我使用pageview时,页面中的dropdownbutton、radiobutton等项目的视图没有更新。请这很重要。

谢谢。

1 个答案:

答案 0 :(得分:1)

最好使用 PageView 作为动态调查表。首先,它为您提供了派上用场的动画。其次,即使您删除或添加 PageView 的子项,它也不会向您抛出错误,而是会帮助您导航到上一页。

在这里,我为您的用例制作了一个片段。基于这个问题,有很多概率取决于答案。我的回答不会涵盖所有用例,但是,您可以自定义 QuestionModel 以满足您的需求。

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final PageController _pageController = PageController();
  List<QuestionModel> _questions = [
    QuestionModel(
        question: 'Is elephant big?',
        questionType: QuestionType.MultipleChoice,
        answerList: ['yes', 'no'],
        isCorrect: false,
        displayDependsOnAnswerOfIndex: null,
        navigateToIndexIfCorrect: 1,
        questionAction: (answer) {
          if (answer == 'yes') {
            return true;
          } else {
            return false;
          }
        }),
    QuestionModel(
        question: 'If big, state the height in feet.',
        questionType: QuestionType.Form,
        answerList: [],
        isCorrect: false,
        displayDependsOnAnswerOfIndex: 0,
        navigateToIndexIfCorrect: null,
        questionAction: (answer) {
          if (answer != null) {
            return true;
          } else {
            return false;
          }
        }),
  ];

  @override
  void dispose() {
    _pageController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    List<QuestionModel> questions = _questions.where((questionModel) {
      if (questionModel.displayDependsOnAnswerOfIndex != null) {
        return (_questions[questionModel.displayDependsOnAnswerOfIndex]
            .isCorrect);
      } else {
        return true;
      }
    }).toList();
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text('Survey'),
        ),
        body: PageView(
          controller: _pageController,
          children: questions.map((questionModel) {
            if (questionModel.questionType == QuestionType.MultipleChoice) {
              return Scaffold(
                body: Column(
                  children: [
                    Text(questionModel.question),
                    Column(
                      children: questionModel.answerList.map((answer) {
                        return ListTile(
                            title: Text(
                              answer,
                              style: TextStyle(
                                fontWeight:
                                    (answer == questionModel.choosenAnswer)
                                        ? FontWeight.bold
                                        : FontWeight.normal,
                              ),
                            ),
                            onTap: () {
                              setState(() {
                                questionModel.choosenAnswer = answer;
                                questionModel.isCorrect =
                                    questionModel.questionAction(answer);
                              });
                              if (questionModel.navigateToIndexIfCorrect !=
                                      null &&
                                  questionModel.isCorrect) {
                                _pageController.animateToPage(
                                  questionModel.navigateToIndexIfCorrect,
                                  duration: Duration(seconds: 1),
                                  curve: Curves.easeInOut,
                                );
                              }
                            });
                      }).toList(),
                    ),
                  ],
                ),
              );
            } else if (questionModel.questionType == QuestionType.Form) {
              return Scaffold(
                //TODO: create implementation of form type question
                body: Column(
                  children: [TextFormField()],
                ),
              );
            } else {
              return Container();
            }
          }).toList(),
        ),
      ),
    );
  }
}

enum QuestionType {
  MultipleChoice,
  Form,
}

class QuestionModel {
  final String question;
  bool isCorrect;
  String choosenAnswer;
  final List<String> answerList;
  final QuestionType questionType;
  final int displayDependsOnAnswerOfIndex;
  final int navigateToIndexIfCorrect;
  final Function questionAction;
  QuestionModel({
    this.question,
    this.choosenAnswer,
    this.questionType,
    this.answerList,
    this.isCorrect,
    this.navigateToIndexIfCorrect,
    this.displayDependsOnAnswerOfIndex,
    this.questionAction,
  });
}