Flutter问答测试插件fastyle_quizz的使用

Flutter问答测试插件fastyle_quizz的使用

fastyle_quizz 是一个用于 fastyle 库的问答小部件集。本文将详细介绍如何在 Flutter 应用中使用 fastyle_quizz 插件,并提供一个完整的示例代码。

完整示例代码

首先,确保你已经在 pubspec.yaml 文件中添加了以下依赖项:

dependencies:
  flutter:
    sdk: flutter
  fastyle_core: ^版本号
  fastyle_quizz: ^版本号
  go_router: ^版本号
  tenhance: ^版本号
  fastyle_buttons: ^版本号

然后,你可以使用以下代码来创建一个包含问答功能的应用:

// Flutter imports:
import 'package:flutter/material.dart';

// Package imports:
import 'package:fastyle_core/fastyle_core.dart';
import 'package:fastyle_quizz/fastyle_quizz.dart';
import 'package:go_router/go_router.dart';
import 'package:tenhance/tenhance.dart';
import 'package:fastyle_buttons/fastyle_buttons.dart';

// Project imports:
import 'package:fastyle_quizz_example/questions.dart';

void main() => runApp(const QuizApp());

class QuizApp extends StatelessWidget {
  const QuizApp({super.key});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return FastApp(
      routesForMediaType: (mediaType) => [
        GoRoute(
          path: '/',
          builder: (_, __) => const QuizPage(),
        ),
      ],
    );
  }
}

class QuizPage extends StatefulWidget {
  const QuizPage({super.key});

  [@override](/user/override)
  QuizPageState createState() => QuizPageState();
}

class QuizPageState extends State<QuizPage> {
  int currentQuestionIndex = 0; // 当前问题的索引
  double currentScore = 0; // 当前得分
  int currentAnswerIndex = -1; // 当前答案的索引

  int totalQuestions = 10; // 总问题数量
  List<bool> answeredCorrectly = List.generate(10, (index) => false); // 跟踪答案
  bool answered = false; // 跟踪当前问题是否已回答
  bool isCorrect = false; // 跟踪所选答案是否正确

  double get currentProgress {
    return (currentQuestionIndex + 1) / totalQuestions * 100;
  }

  List<FastQuestion> questions = kQuestions;

  void handleAnswer(int answerIndex) {
    setState(() {
      final question = questions[currentQuestionIndex];
      isCorrect = answerIndex == question.correctIndex;
      currentAnswerIndex = answerIndex;
      answered = true;

      if (isCorrect) answeredCorrectly[currentQuestionIndex] = true;

      Future.delayed(const Duration(milliseconds: 600), () {
        if (currentQuestionIndex < totalQuestions - 1) {
          setState(() {
            currentQuestionIndex++;
            answered = false;
          });
        } else {
          // 导航到结果屏幕
        }
      });
    });
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return FastSectionPage(
      showAppBar: false,
      child: SafeArea(
        top: false,
        bottom: true,
        child: buildLayout(),
      ),
    );
  }

  Widget buildLayout() {
    return FastMediaLayoutBuilder(
      builder: (context, mediaType) {
        final SizedBox spacer = buildSpacer(mediaType);

        return Column(
          children: [
            buildProgress(context, mediaType),
            spacer,
            Expanded(
              child: Builder(
                builder: (context) {
                  if (mediaType >= FastMediaType.tablet) {
                    return buildLandscapeLayout(context, mediaType);
                  }

                  return buildPortraitLayout(context, mediaType);
                },
              ),
            ),
            kFastSizedBox16,
          ],
        );
      },
    );
  }

  Widget buildProgress(BuildContext context, FastMediaType mediaType) {
    final palette = ThemeHelper.getPaletteColors(context).gray;
    double size = 48.0;

    if (mediaType >= FastMediaType.desktop) {
      size = 96.0;
    } else if (mediaType >= FastMediaType.tablet) {
      size = 64.0;
    }

    return FastCircleProgress(
      strokeWidth: mediaType >= FastMediaType.desktop ? 6.0 : 4.0,
      progressColor: ThemeHelper.colors.getPrimaryColor(context),
      backgroundColor: palette.lightest,
      labelText: (currentQuestionIndex + 1).toString(),
      currentProgress: currentProgress,
      height: size,
      width: size,
    );
  }

  SizedBox buildSpacer(FastMediaType mediaType) {
    SizedBox spacing = kFastSizedBox24;

    if (mediaType >= FastMediaType.desktop) {
      spacing = kFastSizedBox48;
    } else if (mediaType >= FastMediaType.tablet) {
      spacing = kFastSizedBox32;
    }

    return spacing;
  }

  Widget buildPortraitLayout(BuildContext context, FastMediaType mediaType) {
    final question = questions[currentQuestionIndex];
    final SizedBox spacer = buildSpacer(mediaType);

    return LayoutBuilder(builder: (context, constraints) {
      final maxHeight = constraints.maxHeight;

      double heightFactor = 1;

      if (maxHeight > 800) {
        heightFactor = 0.8;
      }

      return FractionallySizedBox(
        heightFactor: heightFactor,
        child: Column(
          children: [
            Expanded(child: buildMedia(context)),
            spacer,
            buildQuestion(context, mediaType),
            spacer,
            Column(
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: buildAnswerOptions(
                context,
                mediaType,
                question.options,
              ),
            ),
          ],
        ),
      );
    });
  }

  Widget buildLandscapeLayout(BuildContext context, FastMediaType mediaType) {
    final question = questions[currentQuestionIndex];

    return LayoutBuilder(builder: (context, constraints) {
      final maxHeight = constraints.maxHeight;
      double heightFactor = 1;
      double widthFactor = 1;

      if (maxHeight > 800) {
        heightFactor = 0.5;
      } else if (maxHeight > 600) {
        heightFactor = 0.65;
      } else if (maxHeight > 480) {
        heightFactor = 0.75;
      }

      if (mediaType >= FastMediaType.large) {
        widthFactor = 0.75;
      } else if (mediaType >= FastMediaType.desktop) {
        widthFactor = 0.8;
      }

      return FractionallySizedBox(
        widthFactor: widthFactor,
        heightFactor: heightFactor,
        child: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Expanded(child: buildMedia(context)),
            kFastHorizontalSizedBox48,
            Expanded(
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.stretch,
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  Expanded(child: buildQuestion(context, mediaType)),
                  ...buildAnswerOptions(context, mediaType, question.options),
                ],
              ),
            )
          ],
        ),
      );
    });
  }

  Widget buildQuestion(BuildContext context, FastMediaType mediaType) {
    final question = questions[currentQuestionIndex];
    double fontSize = kFastFontSize24;

    if (mediaType >= FastMediaType.desktop) {
      fontSize = kFastFontSize40;
    } else if (mediaType >= FastMediaType.tablet) {
      fontSize = kFastFontSize34;
    }

    return ConstrainedBox(
      constraints: const BoxConstraints(minHeight: 60),
      child: Align(
        alignment: mediaType >= FastMediaType.tablet
            ? Alignment.topCenter
            : Alignment.center,
        child: FastTitle(
          textAlign: TextAlign.center,
          text: question.text,
          fontSize: fontSize,
        ),
      ),
    );
  }

  Widget buildMedia(BuildContext context) {
    final palette = ThemeHelper.getPaletteColors(context).blueGray;

    return ColoredBox(
      color: palette.ultraLight,
      child: const Center(
        child: FastSecondaryBody(text: 'Media Illustration'),
      ),
    );
  }

  List<Widget> buildAnswerOptions(
    BuildContext context,
    FastMediaType mediaType,
    List<String> options,
  ) {
    EdgeInsets padding = kFastEdgeInsets4;

    if (mediaType >= FastMediaType.desktop) {
      padding = kFastEdgeInsets8;
    } else if (mediaType >= FastMediaType.tablet) {
      padding = kFastEdgeInsets6;
    }

    return options.asMap().entries.map((entry) {
      return Padding(
        padding: padding,
        child: buildAnswerOption(
          context,
          entry.key,
          entry.value,
        ),
      );
    }).toList();
  }

  Widget buildAnswerOption(BuildContext context, int answerIndex, String text) {
    return FastRaisedButton2(
      onTap: !answered ? () => handleAnswer(answerIndex) : null,
      color: _determineButtonColor(context, answerIndex),
      labelText: text,
    );
  }

  Color _determineButtonColor(BuildContext context, int answerIndex) {
    if (!answered) {
      return ThemeHelper.colors.getPrimaryColor(context);
    }

    final palettes = ThemeHelper.getPaletteColors(context);

    if (currentAnswerIndex == answerIndex) {
      return isCorrect ? palettes.green.dark : palettes.red.dark;
    }

    return palettes.gray.light;
  }
}

更多关于Flutter问答测试插件fastyle_quizz的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter问答测试插件fastyle_quizz的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


fastyle_quizz 是一个用于在 Flutter 应用中创建和管理问答测试(Quiz)的插件。它提供了一些便捷的组件和功能,帮助你快速构建互动式的问答界面。以下是如何使用 fastyle_quizz 插件的基本步骤和示例。

1. 添加依赖

首先,你需要在 pubspec.yaml 文件中添加 fastyle_quizz 依赖:

dependencies:
  flutter:
    sdk: flutter
  fastyle_quizz: ^1.0.0  # 请使用最新版本

然后运行 flutter pub get 来安装依赖。

2. 导入包

在你的 Dart 文件中导入 fastyle_quizz 包:

import 'package:fastyle_quizz/fastyle_quizz.dart';

3. 创建问答数据

你需要准备一些问答数据,通常是一个包含问题和选项的列表。例如:

List<FastQuestion> questions = [
  FastQuestion(
    question: 'What is the capital of France?',
    options: ['Paris', 'London', 'Berlin', 'Madrid'],
    correctAnswerIndex: 0,
  ),
  FastQuestion(
    question: 'Which planet is known as the Red Planet?',
    options: ['Earth', 'Mars', 'Jupiter', 'Saturn'],
    correctAnswerIndex: 1,
  ),
  FastQuestion(
    question: 'Who wrote "Romeo and Juliet"?',
    options: ['William Shakespeare', 'Charles Dickens', 'Mark Twain', 'Jane Austen'],
    correctAnswerIndex: 0,
  ),
];

4. 使用 FastQuizz 组件

在你的 Widget 中使用 FastQuizz 组件来显示问答界面:

class QuizScreen extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Quiz'),
      ),
      body: FastQuizz(
        questions: questions,
        onCompleted: (score) {
          // 当问答完成时调用
          print('Quiz completed! Your score: $score');
          // 这里可以导航到结果页面或显示一个对话框
        },
      ),
    );
  }
}

5. 处理完成事件

FastQuizz 组件提供了一个 onCompleted 回调函数,当用户完成所有问题时会触发该回调。你可以在回调中处理用户的得分,并导航到结果页面或显示一个对话框。

6. 自定义外观和行为

FastQuizz 组件允许你通过传递不同的参数来自定义外观和行为。例如,你可以自定义按钮颜色、文本样式、动画效果等。

FastQuizz(
  questions: questions,
  onCompleted: (score) {
    print('Quiz completed! Your score: $score');
  },
  buttonColor: Colors.blue,
  textStyle: TextStyle(fontSize: 16, color: Colors.black),
  showCorrectAnswer: true,
);

7. 导航到结果页面

你可以在 onCompleted 回调中导航到一个结果页面,显示用户的得分和其他信息。

onCompleted: (score) {
  Navigator.push(
    context,
    MaterialPageRoute(
      builder: (context) => ResultScreen(score: score),
    ),
  );
}

8. 结果页面示例

创建一个简单的结果页面来显示用户的得分:

class ResultScreen extends StatelessWidget {
  final int score;

  ResultScreen({required this.score});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Quiz Result'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              'Your Score: $score',
              style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                Navigator.pop(context);
              },
              child: Text('Retry'),
            ),
          ],
        ),
      ),
    );
  }
}
回到顶部