📜  Flutter API 中的基本测验应用程序(1)

📅  最后修改于: 2023-12-03 15:30:47.883000             🧑  作者: Mango

Flutter API 中的基本测验应用程序

本文介绍了使用 Flutter API 创建基本测验应用程序的步骤和方法。

创建新应用程序

首先,使用 Flutter 命令行工具创建一个新的 Flutter 应用程序。

flutter create quiz_app
cd quiz_app

这将创建一个名为 "quiz_app" 的新目录,并在其中创建一个包含默认模板代码的新 Flutter 应用程序。

添加依赖项

接下来,我们需要添加一些依赖项来构建我们的应用程序。我们将使用两个依赖项:flutter_blocequatable

  • flutter_bloc 用于实现业务逻辑组件(bloc)
  • equatable 用于轻松比较数据模型,从而更轻松地实现 == 方法

打开 pubspec.yaml 文件,并将以下依赖项添加到 dependencies 部分。

dependencies:
  flutter:
    sdk: flutter
  flutter_bloc: ^6.0.0
  equatable: ^2.0.3

保存并运行 flutter packages get 命令以安装新的依赖项。

创建数据模型

在这个应用程序中,我们将使用一个非常简单的数据模型——一个包含问题和答案的问题对象。我们将创建一个新的 Question 类来表示这些问题。

import 'package:equatable/equatable.dart';

class Question extends Equatable {
  final String question;
  final String answer;

  Question({this.question, this.answer});

  @override
  List<Object> get props => [question, answer];
}

注意,我们扩展了 Equatable 类,并实现了 props 属性。这使得使用 == 比较两个 Question 对象变得更容易。

创建业务逻辑组件

我们将使用 flutter_bloc 创建一个新的业务逻辑组件(bloc),该组件将与应用程序的 UI 交互,并处理显示、回答问题等操作。

首先,我们将创建一个新的类,称为 QuizBloc,该类将扩展 bloc 类。我们将添加一个 Question 列表,并定义一些 stream 来控制应用程序的状态。

import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter/cupertino.dart';
import 'package:quiz_app/models/question.dart';

part 'quiz_event.dart';
part 'quiz_state.dart';

class QuizBloc extends Bloc<QuizEvent, QuizState> {
  var _questions = [
    Question(question: '你叫什么名字', answer: 'My name is Jon Snow.'),
    Question(question: '你今年多大了', answer: 'I am 22 years old.'),
    Question(question: '今天天气如何?', answer: 'The weather is great today.')
  ];

  int _currentQuestionIndex = 0;

  QuizBloc() : super(QuizInitial()) {
    add(QuizStarted());
  }

  @override
  Stream<QuizState> mapEventToState(
    QuizEvent event,
  ) async* {
    if (event is QuizStarted) {
      yield QuestionLoadedState(_questions[_currentQuestionIndex]);
    } else if (event is AnswerProvidedEvent &&
        event.answer == _questions[_currentQuestionIndex].answer) {
      if (_currentQuestionIndex < _questions.length - 1) {
        _currentQuestionIndex++;
        yield QuestionLoadedState(_questions[_currentQuestionIndex]);
      } else {
        yield QuizFinishedState();
      }
    } else {
      yield IncorrectAnswerState();
    }
  }
}

这里我们只有一个 _currentQuestionIndex 列表变量,该变量“指向”正确的问题对象。每次回答正确的问题之后,我们会将它提前一个位置并且更新 stream,从而显示一下个问题。

注意,我们将事件和状态分开管理,以使应用程序变得更简洁和可维护。

现在,我们必须定义一些事件和状态,这些事件和状态将用于驱动业务逻辑组件并更新应用程序的状态。

QuizEvent
part of 'quiz_bloc.dart';

abstract class QuizEvent extends Equatable {
  @override
  List<Object> get props => [];
}

class QuizStarted extends QuizEvent {}

class AnswerProvidedEvent extends QuizEvent {
  final String answer;

  AnswerProvidedEvent({@required this.answer});

  @override
  List<Object> get props => [answer];
}
QuizState
part of 'quiz_bloc.dart';

abstract class QuizState extends Equatable {
  @override
  List<Object> get props => [];
}

class QuizInitial extends QuizState {}

class QuestionLoadedState extends QuizState {
  final Question question;

  QuestionLoadedState(this.question);

  @override
  List<Object> get props => [question];
}

class IncorrectAnswerState extends QuizState {}

class QuizFinishedState extends QuizState {}
构建用户界面

这是我们最后的任务:构建用户界面。我们将使用 Flutter 的内置小部件构建我们的应用程序。

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:quiz_app/blocs/quiz/quiz_bloc.dart';
import 'package:quiz_app/models/question.dart';

class QuizPage extends StatelessWidget {
  const QuizPage({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return BlocBuilder<QuizBloc, QuizState>(
      builder: (context, state) {
        if (state is QuestionLoadedState) {
          return Scaffold(
            appBar: AppBar(
              title: Text('Quiz App'),
            ),
            body: Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Text(
                    state.question.question,
                    style: Theme.of(context).textTheme.headline4,
                    textAlign: TextAlign.center,
                  ),
                  SizedBox(height: 20),
                  buildAnswerButton(context, 'Yes'),
                  SizedBox(height: 10),
                  buildAnswerButton(context, 'No'),
                ],
              ),
            ),
          );
        } else if (state is QuizFinishedState) {
          return Scaffold(
            appBar: AppBar(
              title: Text('Quiz App'),
            ),
            body: Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Text(
                    'Congratulation! You have completed the quiz',
                    style: Theme.of(context).textTheme.headline4,
                    textAlign: TextAlign.center,
                  ),
                  SizedBox(height: 20),
                  FlatButton(
                    color: Colors.blue,
                    textColor: Colors.white,
                    onPressed: () {
                      BlocProvider.of<QuizBloc>(context).add(QuizStarted());
                    },
                    child: Text('Restart Quiz'),
                  ),
                ],
              ),
            ),
          );
        } else if (state is IncorrectAnswerState) {
          return Scaffold(
            appBar: AppBar(
              title: Text('Quiz App'),
            ),
            body: Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Text(
                    'Sorry, the answer is incorrect.',
                    style: Theme.of(context).textTheme.headline4,
                    textAlign: TextAlign.center,
                  ),
                  SizedBox(height: 20),
                  FlatButton(
                    color: Colors.blue,
                    textColor: Colors.white,
                    onPressed: () {
                      BlocProvider.of<QuizBloc>(context).add(QuizStarted());
                    },
                    child: Text('Start Over'),
                  ),
                ],
              ),
            ),
          );
        } else {
          return Scaffold(
            appBar: AppBar(
              title: Text('Quiz App'),
            ),
            body: Center(
              child: CircularProgressIndicator(),
            ),
          );
        }
      },
    );
  }

  Widget buildAnswerButton(BuildContext context, String answer) {
    return SizedBox(
      width: 200,
      height: 50,
      child: FlatButton(
        color: Colors.blue,
        textColor: Colors.white,
        onPressed: () {
          BlocProvider.of<QuizBloc>(context)
              .add(AnswerProvidedEvent(answer: answer));
        },
        child: Text(answer),
      ),
    );
  }
}

我们使用了 flutter_bloc 提供的 BlocBuilder 来构建 UI。这样,我们的 UI 将根据业务逻辑组件的状态动态构建。

根据当前的状态,我们通过不同的 Scaffold 和内部的小部件构建不同的 UI。

结论

至此,我们已经构建了一个简单的测验应用程序,并在其中使用了 flutter_blocequatable 库。

我们通过构建一个业务逻辑组件并在用户界面中使用 BlocBuilder 来控制 UI 状态。这种设计模式使我们的应用程序变得更加模块化、可维护性更高。

我们还提供了一些简单的代码示例,以帮助您更好地理解如何使用 Flutter API 创建应用程序。