Tag: dart maps

  • Flutter Maps

    We need to improve the functionality of our app. Currently we have a list of just two questions and no answer is associated with the question.

    var questions = [
          'What\'s your favorite color?',
          'What\'s your favorite animal?'
        ];

    The question should also have the information about available answers. We need more complex object which can group multiple pieces of information together. 

    We could create a new class which has all these features we need and use that class to create objects and that is perfectly fine. However, we’ll use a different data structure that’s built in to Dart and that is a map

    map is a collection of key value pairs. Lets create a map where we have three questions and four answers for each question as below,

    var questions = [
          {
            'questionText': 'What\'s your favorite color?',
            'answers': [ 'Black', 'Red', 'Green', 'White'],
          },
          {
            'questionText': 'What\'s your favorite animal?',
            'answers': [ 'Leopard', 'Markhor', 'Deer', 'Rabbit'],
          },
          {
            'questionText': 'What\'s your favorite lake?',
            'answers': [ 'Saif-ul-Malook', 'Doodi pat sar', 'Katora', 'Saral'],
          },
        ];

    Here is our main.dart file where we are going to map lists to widgets.

    //File Name: main.dart
    import 'package:flutter/material.dart';
    
    /* ./ means look in the main folder where main.dart resides and then the
    *  name of the file which you wana import
     */
    
    import './question.dart';
    import './answer.dart';
    
    /*
    * The arrow function allows us to create a simplified function consisting of a single expression.
    * We can omit the curly brackets and the return keyword
    */
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatefulWidget {
      /*
       * createState() is a method that takes no arguments but returns a State object
       * which is connected to a StatefulWidget
       */
      @override
      State<StatefulWidget> createState() {
        return _MyAppState();
      } //createState()
    } //StatefulWidget
    
    /* A leading underscore makes the property private, here leading underscore will turn
     * this public class in to private class. Now MyAppState class can only be used in
     * main.dart file, in our case in MyApp class.
     */
    class _MyAppState extends State<MyApp> {
      var _questionIndex = 0;
    
      void _answerQuestion() {
        setState(() {
          _questionIndex++;
        });
        print(_questionIndex);
      }
    
      @override
      Widget build(BuildContext context) {
        var questions = [
          {
            'questionText': 'What\'s your favorite color?',
            'answers': ['Black', 'Red', 'Green', 'White'],
          },
          {
            'questionText': 'What\'s your favorite animal?',
            'answers': ['Leopard', 'Markhor', 'Deer', 'Rabbit'],
          },
          {
            'questionText': 'What\'s your favorite lake?',
            'answers': ['Saif-ul-Malook', 'Doodi pat sar', 'Katora', 'Saral'],
          },
        ];
        return MaterialApp(
          /*
          * A Scaffold Widget provides a framework which implements the basic material design visual
          * layout structure of the flutter app.
           */
          home: Scaffold(
            appBar: AppBar(
              title: Text('First Flutter App'),
            ),
            body: Column(
              children: <Widget>[
                Question(
                  questions[_questionIndex]['questionText'],
                ),
                /*
                * for answers, transform list of maps in to list of widgets
                * map() method executes a function (anonymous) which we have to pass as an argument.
                * it returns a widget
                * ... is spread operator, it takes a list and pulls all the values in the list out of it
                * and add them to surrounding list as individual value. Means, we don't add a list to a list
                * but values of the list to a list.
                 */
                ...(questions[_questionIndex]['answers'] as List<String>)
                    .map((answer) {
                  return Answer(_answerQuestion, answer);
                }).toList(),
              ],
            ),
          ),
        );
      } //build()
    } //MyApp()
    

    Here is answer.dart file

    //FileName: answer.dart
    import 'package:flutter/material.dart';
    
    class Answer extends StatelessWidget {
      final Function selectHandler;
      final String answerText;
    
      Answer(this.selectHandler, this.answerText);
    
      @override
      Widget build(BuildContext context) {
        return Container(
          width: double.infinity, ////double.infinity means occupy the whole screen (width in this case)
          margin: EdgeInsets.all(10), //apply margin of 10 pts to all 4 sides
          /*
          * We have provided 3 named arguments here to ElevatedButton()
          * 1. child: which is a Text() widget
          * 2. onPressed: which is a function we get via constructor
          * 3. style: where we change the color, padding and text style
           */
          child: ElevatedButton(
            child: Text(answerText),
            //onPressed takes a function
            onPressed: selectHandler,
            style: ElevatedButton.styleFrom(
              primary: Colors.blue, //the button's background color
              onPrimary: Colors.white, //the button's text color
    
              padding: EdgeInsets.symmetric(horizontal: 50, vertical: 20),
              textStyle: TextStyle(fontSize: 30, fontWeight: FontWeight.bold),
            ), //.styleFrom
          ), //ElevatedButton
        ); //Container
      }
    }
    

    The question widget will remain unchanged.

    //FileName: question.dart
    import 'package:flutter/material.dart';
    
    class Question extends StatelessWidget {
      /*
      * final keywords tells dart that this value will never change after its
      * initialization here int he constructor
       */
      final String questionText;
    
      /* Lets have a constructor to initialize this widget class questionText
      *  Now the first positional argument passed to this constructor will be stored in
      *  questionText variable
       */
      Question(this.questionText);
    
      @override
      Widget build(BuildContext context) {
        return Container(
          width: double.infinity, //double.infinity means occupy the whole screen (width in this case)
          margin: EdgeInsets.all(10), //apply margin of 10 pts to all 4 sides
          child: Text(
            questionText,
            style: TextStyle(fontSize: 26),
            textAlign: TextAlign.center,
          ), //Text
        ); //Container()
      } //build
    } //Question
    

    Here is the output

    Output – Mapping Lists to Widgets

    Happy Coding!