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!