Open In App

Basic Quiz App In Flutter API

Improve
Improve
Like Article
Like
Save
Share
Report

Flutter API is an open-source software development kit for building beautiful UI which is natively compiled. Currently, it is available is a stable version for IOS and Android OS.

In this app we are going to have the features or modules mentioned below:

  • Five multiple-choice questions ( more questions can be added ).
  • Four selectable options for each question in the form of buttons except the last one.
  • The score will be calculated based on the option selected for each question (Internally).
  • And based on the final score a remark will be shown at the end of the quiz in addition to the score and restart button.
  • There are two screens in the app home (where questions will be shown) and the result screen ( where score and remark will be shown).
  • The whole app will be separated into five different modules namely main.dart, question.dart, answer.dart,quiz.dart and result.dart.

Making this app will give you a good revision of flutter and dart basics. As we are covering a lot of concepts such as:

  • Showing Widgets on the screen.
  • Recycling Widgets.
  • Changing Screens.
  • Internal Logic
  • and else.

To start making the app we first have to create a flutter project which will give us many files and folders. In the Lib folder, there is a main.dart file already present. And now in the same folder rest, four files should be created:- 

  • question.dart
  • answer.dart
  • quiz.dart and
  • result.dart

Step 1: In step one we are going to

  • Create MyApp class and make it stateful.
  • Add questions for the home screen.
  • Create a widget tree for the home screen.

Starting with the main.dart file

Dart




import 'package:flutter/material.dart';
 
import './quiz.dart';
import './result.dart';
 
void main() => runApp(const MyApp());
 
class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);
 
  @override
  State<StatefulWidget> createState() {
    return _MyAppState();
  }
}
 
class _MyAppState extends State<MyApp> {
  final _questions = const [
    {
      'questionText': 'Q1. Who created Flutter?',
      'answers': [
        {'text': 'Facebook', 'score': -2},
        {'text': 'Adobe', 'score': -2},
        {'text': 'Google', 'score': 10},
        {'text': 'Microsoft', 'score': -2},
      ],
    },
    {
      'questionText': 'Q2. What is Flutter?',
      'answers': [
        {'text': 'Android Development Kit', 'score': -2},
        {'text': 'IOS Development Kit', 'score': -2},
        {'text': 'Web Development Kit', 'score': -2},
        {
          'text':
              'SDK to build beautiful IOS, Android, Web & Desktop Native Apps',
          'score': 10
        },
      ],
    },
    {
      'questionText': ' Q3. Which programming language is used by Flutter',
      'answers': [
        {'text': 'Ruby', 'score': -2},
        {'text': 'Dart', 'score': 10},
        {'text': 'C++', 'score': -2},
        {'text': 'Kotlin', 'score': -2},
      ],
    },
    {
      'questionText': 'Q4. Who created Dart programming language?',
      'answers': [
        {'text': 'Lars Bak and Kasper Lund', 'score': 10},
        {'text': 'Brendan Eich', 'score': -2},
        {'text': 'Bjarne Stroustrup', 'score': -2},
        {'text': 'Jeremy Ashkenas', 'score': -2},
      ],
    },
    {
      'questionText':
          'Q5. Is Flutter for Web and Desktop available in stable version?',
      'answers': [
        {
          'text': 'Yes',
          'score': -2,
        },
        {'text': 'No', 'score': 10},
      ],
    },
  ];
 
  var _questionIndex = 0;
  var _totalScore = 0;
 
  void _resetQuiz() {
    setState(() {
      _questionIndex = 0;
      _totalScore = 0;
    });
  }
 
  void _answerQuestion(int score) {
    _totalScore += score;
 
    setState(() {
      _questionIndex = _questionIndex + 1;
    });
    // ignore: avoid_print
    print(_questionIndex);
    if (_questionIndex < _questions.length) {
      // ignore: avoid_print
      print('We have more questions!');
    } else {
      // ignore: avoid_print
      print('No more questions!');
    }
  }
 
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Geeks for Geeks'),
          backgroundColor: const Color(0xFF00E676),
        ),
        body: Padding(
          padding: const EdgeInsets.all(30.0),
          child: _questionIndex < _questions.length
              ? Quiz(
                  answerQuestion: _answerQuestion,
                  questionIndex: _questionIndex,
                  questions: _questions,
                ) //Quiz
              : Result(_totalScore, _resetQuiz),
        ), //Padding
      ), //Scaffold
      debugShowCheckedModeBanner: false,
    ); //MaterialApp
  }
}


In Flutter main.dart file is the entry point from which the code starts executing. In the main.dart file firstly material design package has been imported in addition to quiz.dart and result.dart . Then a function runApp has been created with parameter as MyApp. After the declaration of class MyApp which is a stateful widget, the state of class MyApp has been laid out. Now that is followed by the four questions along with their respective answer options & score. And at the end, we have the widget tree for the home screen, which shows the appBar with title, body with the questions and options. At the last, the debug banner has been disabled. We have classes like Quiz or Result, that will be defined in the following pages.

Step 2: In step two we will create

  • Class Quiz (used in the home screen)
  • Widget tree for class Quiz

quiz.dart

Dart




import 'package:flutter/material.dart';
 
import './answer.dart';
import './question.dart';
 
class Quiz extends StatelessWidget {
  final List<Map<String, Object>> questions;
  final int questionIndex;
  final Function answerQuestion;
 
  const Quiz({
    Key? key,
    required this.questions,
    required this.answerQuestion,
    required this.questionIndex,
  }) : super(key: key);
 
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Question(
          questions[questionIndex]['questionText'].toString(),
        ), //Question
        ...(questions[questionIndex]['answers'] as List<Map<String, Object>>)
            .map((answer) {
          return Answer(
              () => answerQuestion(answer['score']), answer['text'].toString());
        }).toList()
      ],
    ); //Column
  }
}


This is the quiz.dart which was already imported in the main.dart file. In this file the class Quiz is being defined which is used in the main.dart file. Class Quiz has been extended as stateless widget as it need not change any time in the run cycle of the app, which is followed by constructor Quiz. Then we have the widget tree that defines the structure of the class Quiz which is basically the questions and their options. Again we have the class Question which will be defined in the question.dart file.

Step 3: In step three we will create

  • Class Question (again used in the home screen)
  • Widget tree for the class Question

question.dart

Dart




import 'package:flutter/material.dart';
 
class Question extends StatelessWidget {
  final String questionText;
 
  const Question(this.questionText, {Key? key}) : super(key: key);
 
  @override
  Widget build(BuildContext context) {
    return Container(
      width: double.infinity,
      margin: const EdgeInsets.all(10),
      child: Text(
        questionText,
        style: const TextStyle(fontSize: 28),
        textAlign: TextAlign.center,
      ), //Text
    ); //Container
  }
}


This question.dart file has already been imported into the quiz.dart file, which uses the class Question. The class Question would be a stateless one similar to the Quiz it needs not change in the run cycle. Then we have the constructor Question which is followed by the widget tree that gives structure to the Question widget.

Step 4: In step four we will create

  • Class Answer (used in the home screen)
  • Widget tree for class Answer

answer.dart

Dart




import 'package:flutter/material.dart';
 
class Answer extends StatelessWidget {
  final Function selectHandler;
  final String answerText;
 
  const Answer(this.selectHandler, this.answerText, {Key? key})
      : super(key: key);
 
  @override
  Widget build(BuildContext context) {
    // use SizedBox for white space instead of Container
    return SizedBox(
      width: double.infinity,
      child: ElevatedButton(
        onPressed: selectHandler(),
        style: ButtonStyle(
            textStyle:
                MaterialStateProperty.all(const TextStyle(color: Colors.white)),
            backgroundColor: MaterialStateProperty.all(Colors.green)),
        child: Text(answerText),
      ),
 
      // RaisedButton is deprecated and should not be used
      // Use ElevatedButton instead
 
      // child: RaisedButton(
      //   color: const Color(0xFF00E676),
      //   textColor: Colors.white,
      //   onPressed: selectHandler(),
      //   child: Text(answerText),
      // ), //RaisedButton
    ); //Container
  }
}


This answer.dart file was also imported in the quiz.dart file. This file contains the Answer class which was used in the quiz.dart file. Again similar to Quiz and Question class Answer would also be stateless.  In the class Answer function, selectHandler and string answerText have been passed using the keyword final as they belong to the stateful widget and hence need to be specified immutable, and not doing so will result in a dart analysis warning. That is followed by the constructor and the usual widget tree to give it a structure.

Step 5: In the last step we will create

  • Class Result for (result screen)
  • Remark logic
  • Class Result widget tree

File: result.dart

Dart




// ignore_for_file: avoid_print
 
import 'package:flutter/material.dart';
 
class Result extends StatelessWidget {
  final int resultScore;
  final Function resetHandler;
 
  const Result(this.resultScore, this.resetHandler, {Key? key})
      : super(key: key);
 
  //Remark Logic
  String get resultPhrase {
    String resultText;
    if (resultScore >= 41) {
      resultText = 'You are awesome!';
      print(resultScore);
    } else if (resultScore >= 31) {
      resultText = 'Pretty likeable!';
      print(resultScore);
    } else if (resultScore >= 21) {
      resultText = 'You need to work more!';
    } else if (resultScore >= 1) {
      resultText = 'You need to work hard!';
    } else {
      resultText = 'This is a poor score!';
      print(resultScore);
    }
    return resultText;
  }
 
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Text(
            resultPhrase,
            style: const TextStyle(fontSize: 26, fontWeight: FontWeight.bold),
            textAlign: TextAlign.center,
          ), //Text
          Text(
            'Score ' '$resultScore',
            style: const TextStyle(fontSize: 36, fontWeight: FontWeight.bold),
            textAlign: TextAlign.center,
          ), //Text
          TextButton(
            onPressed: resetHandler(),
            child: Container(
              color: Colors.green,
              padding: const EdgeInsets.all(14),
              child: const Text(
                'Restart Quiz',
                style: TextStyle(color: Colors.blue),
              ),
            ),
          ),
          // FlatButton is deprecated and should not be used
          // Use TextButton instead
 
          // FlatButton(
          //   child: Text(
          //     'Restart Quiz!',
          //   ), //Text
          //   textColor: Colors.blue,
          //   onPressed: resetHandler(),
          // ), //FlatButton
        ], //<Widget>[]
      ), //Column
    ); //Center
  }
}


This result.dart file had been imported in the main.dart file already as the class Result is defined in this file. Class results will not change in the app run cycle therefore it is a stateless widget. As subclasses or variables which are used in the stateful widget need to be made immutable keyword final has been used, it is followed by the Result keyword. After that, we have the resulting logic which decided which remark would be shown after the quiz bases on the final score. And at last, we have the widget tree that defines the structure of the class Result.

And now after completing the result.dart file our basic quiz app is completed now. We can preview the app in any physical device or emulator or even in the browser. It should look something like this.

After the app has been finalized, apk for the app can be generated by giving the command ‘flutter build apk’ in the terminal.



Last Updated : 18 Apr, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads