Flutter Display Widgets Conditionally

Our application have a bug, it crashes when all questions are answered. As shown below

Output – App crash

Instead of crashing the app, it would be nice if we display some message when the questions list is exhausted. Here, I’ll output a different widget once all questions are answered.

Here we’ll use inline if condition to display either questions and answers or a custom text once questions are exhaused.

Inline if else is a single line statement where we have a condition then after question mark is the true scenario execution and after colon is the false scenario execution.

 

var num1 = 10;
var num2 = 20;

//normal if else statement
if ( num1 > num2 )
  print('Number 1 is greater');
else
  print('Number 2 is greater');

//single line if else statement
( num1 > num2 ) ? print('Number 1 is greater') : print('Number 2 is greater');

//both will have the same output, Number 2 is greater.

Here is our main.dart code where we have implemented inline if else statement and show widgets conditionally. We stop showing questions and answers once all the questions have been answered.

//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;

  final questions = const [
    {
      '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'],
    },
  ];

  void _answerQuestion() {
    setState(() {
      _questionIndex++;
    });
  }

  @override
  Widget build(BuildContext context) {
    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: _questionIndex < questions.length
            ? 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(),
                ],
              )
            : Center(child: Text('All caught up')),
      ),
    );
  } //build()
} //MyApp()
//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
//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
  }
}

Inline if else was a simple addition in our app code where we showed widgets conditionally and made the app more user friendly.

Happy Coding!

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!

Flutter Button Formatting and Passing Call back Function

We had already created a new widget for questions. Now, we’ll create a new widget for answers. 

Create a new file answer.dart besides main.dart and add the following code there.

//FileName: answer.dart
import 'package:flutter/material.dart';

class Answer extends StatelessWidget {
  final Function selectHandler;

  Answer(this.selectHandler);

  @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('Answer1'),
        //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
  }
}

Here is question.dart file previously created.

//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

In our main.dart file we’ll add the import for answer.dart and will replace ElevatedButton() code with this Answer() code and will add SizedBox() for spacing.

Now, our main.dart file’s code is simple and easy to understand.

//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 = [
      'What\'s your favorite color?',
      'What\'s your favorite animal?'
    ];
    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],
            ),
            Answer(_answerQuestion),
            SizedBox(height: 16),
            Answer(_answerQuestion),
            SizedBox(height: 16),
            Answer(_answerQuestion),
          ],
        ),
      ),
    );
  } //build()
} //MyApp()
Output

This is a lot to digest but I have made things easy to understand by taking you along using step by step approach.

Happy Coding!

Flutter Widget Formatting

//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
Output – Formatted Flutter Widget

Happy Coding!

Flutter Create a New Custom Widget

Let’s create a new widget that will wrap this question text.

Text(
      questions[_questionIndex],
      ),

To create such a new widget, we can simply add a new class. Now we can do this in the same file (main.dart) we previously worked in but a good convention rule is to only have one widget per file. There are rare exceptions to that rule, for example we have two widgets that really only work together and we don’t really plan on reusing a widget in other files but generally, you want to have one widget per file.

Therefore, here I’ll add a new file next to the main.dart file and I’ll name it question.dart and this should hold my question widget. 

 

//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 Text(questionText);
  } //build()
} //Question

Now, in our main.dart we need to import that Question widget by

/* ./ means look in the main folder where main.dart resides and then the
*  name of the file which you wana import
 */

import './question.dart';

It means that everything that is available in question.dart is now available in this file main.dart Please note that we didn’t had a leading underscore in Question class widget because that will make it private and we want to use it in main.dart file.

Now, in our main.dart file we’ll replace the Text() widget with Question() widget thus providing the same argument.

Question(
        questions[_questionIndex],
        ),

Question() constructor expects a String which we are passing from questions list based upon questionIndex.

Here is our main.dart file.

//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';

/*
* 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 = [
      'What\'s your favorite color?',
      'What\'s your favorite animal?'
    ];
    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],
            ),
            ElevatedButton(
              child: Text('Answer1'),
              //onPressed takes a function
              onPressed: _answerQuestion,
            ),
            ElevatedButton(
              child: Text('Answer2'),
              onPressed: () => print('Answer2 chosen!'),
            ),
            ElevatedButton(
              child: Text('Answer3'),
              onPressed: () {
                //...multiline function body
                print('Answer3 chosen');
              },
            ),
          ],
        ),
      ),
    );
  } //build()
} //MyApp()

Now instead of using Text() widget we use our own widget Question where we also use a Text() widget. Of course for the simple restructuring, it is not useful, nonetheless it is a good idea to split your widgets or app in to smaller custom widgets that can help with performance. It can make our rebuilds more efficient and also it is easier for us to manage our code.

If our widget structure had complex logic and code as compared to a simple Text() widget then our main.dart file would be much simple and compact as soon as we move that in to a separate widget.

If we run our app it will have the same functionality and look as before.

Output

Output – First Question

and if we press Answer1 it behaves the same as before.

Output – Second Question

Happy Coding!

Flutter Private Properties

Unlike Java, Dart doesn’t have the keywords public, protected, and private. If an identifier starts with an underscore _, it’s private to its library. Libraries not only provide APIs, but are a unit of privacy: identifiers that start with an underscore _ are visible only inside the library.

Every Dart app is a library, even if it doesn’t use a library directive. The import and library directives can help you create a modular and shareable code base.

//File Name: main.dart
import 'package:flutter/material.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 = [
      'What\'s your favorite color?',
      'What\'s your favorite animal?'
    ];
    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>[
            Text(questions[_questionIndex]),
            ElevatedButton(
              child: Text('Answer1'),
              //onPressed takes a function
              onPressed: _answerQuestion,
            ),
            ElevatedButton(
              child: Text('Answer2'),
              onPressed: () => print('Answer2 chosen!'),
            ),
            ElevatedButton(
              child: Text('Answer3'),
              onPressed: () {
                //...multiline function body
                print('Answer3 chosen');
              },
            ),
          ],
        ),
      ),
    );
  } //build()
} //MyApp()

Output

Output

Happy Coding!

Flutter Need for StatefulWidget

Continuing from our last blog post “Flutter/Dart Anonymous Function” , in this post we have added a list of questions in build() for now, with only two questions.

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

We have introduced a variable ‘questionIndex’ to keep track and change the question on the go. We increment this variable questionIndex in answerQuestion() function in MyApp class.

var questionIndex = 0;

  void answerQuestion() {
    questionIndex++;
    print(questionIndex);
    //print('Answer chosen!');
  }

Instead of display a static question in the Text() widget, we now display a question from questions list using questionIndex.

Text(questions[questionIndex]

Here is the full application code snippet.

//File Name: main.dart
import 'package:flutter/material.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 StatelessWidget {
  var questionIndex = 0;

  void answerQuestion() {
    questionIndex++;
    print(questionIndex);
    //print('Answer chosen!');
  }

  @override
  Widget build(BuildContext context) {
    var questions = [
      'What\'s your favorite color?',
      'What\'s your favorite animal?'
    ];
    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>[
            Text(questions[questionIndex]),
            ElevatedButton(
              child: Text('Answer1'),
              //onPressed takes a function
              onPressed: answerQuestion,
            ),
            ElevatedButton(
              child: Text('Answer2'),
              onPressed: () => print('Answer2 chosen!'),
            ),
            ElevatedButton(
              child: Text('Answer3'),
              onPressed: () {
                //...multiline function body
                print('Answer3 chosen');
              },
            ),
          ],
        ),
      ),
    );
  } //build()
} //MyApp()

Output

Output

What happens if we first Answer1 button? The question should change, right? but it doesn’t change because we are trying to change the internal state of the widget.

Remember, we can’t manage the state of a StatelessWidget, for that we need StatefulWidget which we’ll cover in next blog post.

Flutter/Dart Anonymous Function

Anonymous function is called anonymous because it has no name. Anonymous function is always a good idea if you never need to call it from anywhere else, it has no name and you can’t call it from anywhere else.

//File Name: main.dart
import 'package:flutter/material.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 StatelessWidget {
  void answerQuestion() {
    print('Answer chosen!');
  }

  @override
  Widget build(BuildContext context) {
    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>[
            Text('The question'),
            ElevatedButton(
              child: Text('Answer1'),
              //onPressed takes a function
              onPressed: answerQuestion,
            ),
            ElevatedButton(
              child: Text('Answer2'),
              onPressed: () => print('Answer2 chosen!'),
            ),
            ElevatedButton(
              child: Text('Answer3'),
              onPressed: () {
                //...multiline function body
                print('Answer3 chosen');
              },
            ),
          ],
        ),
      ),
    );
  } //build()
} //MyApp()

Output

Output
Console Output

Happy Coding!

Flutter Functions on Button Click

Added: In the previous post “Flutter Column Layout Widget” we created a Column() layout widget that took ‘children’ argument which was a list of Widgets, one Text() widget and three ElevatedButton() widgets.

ElevatedButton() widget took two arguments.

  1. child which takes a Text() widget i.e, text of the button.
  2. onPressed which we passed null at that time.

Here is the snapshot of that code snipped.

body: Column(
          children: <Widget>[
            Text('The question'),
            ElevatedButton(child: Text('Answer1'), onPressed: null,),
            ElevatedButton(child: Text('Answer2'), onPressed: null,),
            ElevatedButton(child: Text('Answer3'), onPressed: null,),
          ], //<Widget>[]
        ), //Column()

Since we were passing null to onPressed, all three buttons were disabled and we can’t click/tap these.

Now we’ll create a function (answerQuestion) in MyApp class that will be passed to ElevatedButton() onPressed argument. In that function we’ll just print some text on the console.

 

//File Name: main.dart
import 'package:flutter/material.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 StatelessWidget {
  void answerQuestion(){
    print('Answer chosen!');
  }
  @override
  Widget build(BuildContext context) {
    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>[
            Text('The question'),
            ElevatedButton(
              child: Text('Answer1'),
              //onPressed takes a function
              onPressed: answerQuestion,
            ),
            ElevatedButton(
              child: Text('Answer2'),
              onPressed: answerQuestion,
            ),
            ElevatedButton(
              child: Text('Answer3'),
              onPressed: answerQuestion,
            ),
          ],
        ),
      ),
    );
  } //build()
} //MyApp()

Output: The buttons are enabled now and we can tap them and when we tap a button we’ll see ‘Answer chosen!’ text in console.

Output: Connect Functions with Button Click
Console Output

This was a simple addition of a function answerQuestion() in MyApp class and we passed that function to the ElevatedButton() onPressed argument.

Happy Coding!

Dart Named Arguments

There are two types of arguments for a constructor in dart.

  1. Positional arguments – These are commonly used. For Positional arguments you have to remember which argument goes in to which place.
  2. Named arguments – This is a new concept if you belong to C++, Java or PHP. For Named Arguments you don’t need to remember the place/position of the argument. Named Arguments are optional but can be made mandatory using @required
class Person{

  String name="";
  int age=0;
  
  Person({String inputName="", int inputAge=0}){

    this.name = inputName;
    this.age = inputAge;
  }//Person()
  
  Person.veryOld(this.name){
    age = 60;
  }//Person.veryOld()
}//Person


void main() {

  var p1 = Person(inputName: "Rizwan", inputAge: 34);
  var p2 = Person(inputName: "Ali", inputAge: 32);
  var p3 = Person.veryOld("Usama");

  print(p1.name); //Rizwan
  print(p1.age);  //34

  print(p2.name); //Ali
  print(p2.age);  //32

  print(p3.name); //Usama
  print(p3.age);  //60
  
}

Dart Constructor

class Person {

  String name="";
  int age=0;
  
  Person(String inputName, int inputAge){
    this.name = inputName;
    this.age = inputAge;
  }//Person()
}//Person

void main() {

  var p1 = Person("Rizwan", 34);
  var p2 = Person("Ali", 32);
  
  print(p1.name); //Rizwan
  print(p1.age);  //34
  
  print(p2.name); //Ali
  print(p2.age);  //32
}

In this constructor we are using positional arguments i.e, inputName and inputAge instead of named arguments.