378

So far whenever I needed to use a conditional statement within a Widget I have done the following (Using Center and Containers as simplified dummy examples):

new Center(
  child: condition == true ? new Container() : new Container()
)

Though when I tried using an if/else statement it would lead to an Dead code warning:

new Center(
  child: 
    if(condition == true){
      new Container();
    }else{
      new Container();
    }
)

Interestingly enough I tried with a switch case statement and it gives me the same warning and thus I cannot run the code. Am I doing something wrong or is it so that one cannot use if/else or switch statements without flutter thinking there is dead code?

2
  • 2
    If you want to insert a block where widgets should be instantiated you probably better build your widget in class methods Apr 8, 2018 at 0:15
  • 1
    Center( child:Builder(builder:(context){ if(true) return widget1(); else return widget2(); }) ) Jun 14, 2020 at 6:05

32 Answers 32

480

Actually you can use if/else and switch and any other statement inline in dart / flutter.

Use a builder

  Widget build(BuildContext context) {
    return Container(
      child: Builder(
        builder: (context) {
          if (true) //
            return "tis true";

          return "anything but true";
        },
      ),
    );
  }

or an immediate anonymous function

  Widget build(BuildContext context) {
    return Container(child: () {
      if (value == 1) {
        return Text('tis true');
      }
      return Text('anything but true');
    }());
  }

I would heavily recommend against putting too much logic directly with your UI 'markup' but I found that type inference in Dart needs a little bit of work so it can be sometimes useful in scenarios like that.

Use the ternary operator

condition ? Text("True") : null,

Use If or For statements or spread operators in collections

children: [
  ...manyItems,
  oneItem,
  if(canIKickIt)
    ...kickTheCan
  for (item in items)
    Text(item)

Use a method

child: getWidget()

Widget getWidget() {
  if (x > 5) ...
  //more logic here and return a Widget

EDIT - new with Dart 3.0

Dart 3.0 adds new functionality such as if-case & switch expressions in order to use pattern matching, destructuring, guard clauses.
https://dart.dev/language/patterns

Switch Expressions

We can now use switch as an expression. https://dart.dev/language/branches#switch-expressions

child: switch (task) {
  Task_completed(:date) => Text("completed on $date"),
  Task_overdue(:priority) => Text("$priority"),
},

if-case (new to Dart 3.0)

Use if-case instead of switch when you have a single or small number of conditions to check. https://dart.dev/language/branches#if-case

return ListView(children: [
  Text('header'),
  if (pair case [int x, int y]) // 
    Text('Coordinates: ($x, $y)') // 
  else
    Text('No coordinates given'),
]);
7
  • 11
    Just a note if anyone gets stuck, if you are using Provider to rebuild your widgets on global state change, and you are getting data via "Provider.of", your conditional statement may not be re-evaluated until some other action rebuilds your widget. You need to be getting your conditional variable via "Consumer" that is being returned to the Widget build function, then your conditional statement should be properly re-evaluated as global state changes. Jan 5, 2020 at 0:59
  • 1
    One of the best things for good practices in dart/flutter
    – Kohls
    Sep 29, 2020 at 12:44
  • which one is better in ternary code? using null or empty Container() ?
    – buncis
    Apr 17, 2021 at 18:58
  • where can u put the style in, by the immediate anonymous funtion? for exampe: style: TextStyle(color: Colors.white),
    – jauki
    Jun 26, 2021 at 12:12
  • I was getting an error that Column cannot contain null values for the ternary and empty Container() was a work around
    – Drew
    Jul 5, 2021 at 14:54
290

I personally use if/else statement in children with this kind of block statement. It only supports on Dart version 2.3.0 above.

if / else

Column(
    children: [
        if (_selectedIndex == 0) ...[
          DayScreen(),
        ] else ...[
          StatsScreen(),
        ],
    ],
 ),

if / else if

Column(
    children: [
        if (_selectedIndex == 0) ...[
          DayScreen(),
        ] else if(_selectedIndex == 1)...[
          StatsScreen(),
        ],
    ],
 ),

multiple widgets example

Column(
    children: [
        if (_selectedIndex == 0) ...[
          DayScreen(),
          AboutScreen(),
          InfoScreen(),
        ] else if(_selectedIndex == 1)...[
          HomeScreen(),
          StatsScreen(),
        ],
    ],
 ),
8
  • 72
    That ...[] trick is awesome. It's a detail that no other answer mentioned, but it's very useful if you want to add multiple widgets conditionally.
    – Nato Boram
    Jan 29, 2021 at 16:14
  • does any one know this works starting from which version of flutter? Dec 4, 2021 at 8:56
  • @ShadyMohamedSherif which version you are using now? I started using flutter from 1.17 and it is already working since then. This is nothing special, it's just spreading a list of widgets.
    – brendan
    Dec 5, 2021 at 5:56
  • @brendan, IDK, seems kind of special since Dart won't respond to more colloquial forms of if/else statements in this context, including ternary, but does work correctly using a spread syntax that a lot (most?) people don't know about. My initial attempts were all trying to choose between different lists at the children level, not inside the children list. Seems like a place for Dart to improve. Jan 29, 2023 at 20:29
  • why do we need the three dots? please
    – Mbebwo
    Jul 6, 2023 at 21:32
106

In Dart, if/else and switch are statements not expressions. They don't return a value so you can't pass them to constructor params. If you have a lot of conditional logic in your build method, then it is a good practice to try and simplify it. For example, you can move self-contained logic to methods, and use if/else statements to initialize local variables which you can later use.

Using a method and if/else

Widget _buildChild() {
  if (condition) {
    return ...
  }
  return ...
}

Widget build(BuildContext context) {
  return new Container(child: _buildChild());
}

Using an if/else

Widget build(BuildContext context) {
  Widget child;
  if (condition) {
    child = ...
  } else {
    child = ...
  }
  return new Container(child: child);
}
2
  • 1
    This should be the correct answer! Thank you for this clarification it helped me!
    – Slamit
    Jul 17, 2020 at 7:42
  • 1
    What if you have a deep tree, and conditionally want to render something in the tree? Duplicate? Or will I have to split the tree somehow?
    – Jeppe
    Jun 25, 2021 at 17:52
84

In such a case I would recommand using the ternary operator:

child: condition ? Container() : Center()

and try to avoid code of the form:

if (condition) return A else return B

which is needlessly more verbose than the ternary operator.

But if more logic is needed you may also:

Use the Builder widget

The Builder widget is meant for allowing the use of a closure when a child widget is required:

A platonic widget that calls a closure to obtain its child widget.

It is convenient anytime you need logic to build a widget, it avoids the need to create a dedicated function.

You use the Builder widget as the child, you provide your logic in its builder method:

Center(
  child: Builder(
    builder: (context) {
      // any logic needed...
      final condition = _whateverLogicNeeded();
      
      return condition
          ? Container();
          : Center();
    }
  )
)

The Builder provides a convenient place to hold the creational logic. It is more straightforward than the immediate anonymous function proposed by atreeon.

Also I agree that the logic should be extracted from the UI code, but when it's really UI logic it is sometimes more legible to keep it there.

1
  • this worked for me pretty well for drawer items click and updating body Sep 24, 2020 at 18:38
48

For the record, Dart 2.3 added the ability to use if/else statements in Collection literals. This is now done the following way:

return Column(children: <Widget>[
  Text("hello"),
  if (condition)
     Text("should not render if false"),
  Text("world")
],);

Flutter Issue #28181 - Inline conditional rendering in list

7
  • I have dart 2.5 but I get error running above code. It says ` this code is required to be compatible with earlier versions. try updating SDK constraints`
    – Aseem
    Dec 14, 2019 at 19:50
  • emmm, interesting~
    – Haojen
    Dec 16, 2019 at 9:53
  • Do they add for loop feature? if so how to implement it? Jan 10, 2020 at 11:12
  • Doesn't work with a single widget like AppBar -> leading: or child: Mar 8, 2020 at 9:27
31

I found out that an easy way to use conditional logic to build Flutter UI is to keep the logic outside of the UI. Here is a function to return two different colors:

Color getColor(int selector) {
  if (selector % 2 == 0) {
    return Colors.blue;
  } else {
    return Colors.blueGrey;
  }
}

The function is used below to to set the background of the CircleAvatar.

new ListView.builder(
  itemCount: users.length,
  itemBuilder: (BuildContext context, int index) {
    return new Column(
      children: <Widget>[
        new ListTile(
          leading: new CircleAvatar(
            backgroundColor: getColor(index),
            child: new Text(users[index].name[0])
          ),
          title: new Text(users[index].login),
          subtitle: new Text(users[index].name),
        ),
        new Divider(height: 2.0),
      ],
    );
  },
);

Very neat as you can reuse your color selector function in several widgets.

1
  • 3
    I tried this and worked for me the exact way. Thanks
    – Ajay Kumar
    Jun 17, 2019 at 14:55
24

The simplest way:

// the ternary operator:
<conditon>
  ? Widget1()
  : Widget2()

// Or:
if (condition)
    Widget1()

// With else/ if else
if (condition1)
    Widget1()
else if (condition2)
    Widget2()
else
    Widget3(),

If you want to render MULTIPLE WIDGETS for one condition, you can use the spread operator (for that, you must be inside a Row, Column or Stack widget):

if (condition) ...[
    Widget1(),
    Widget2(),
  ],

// with else / else if:
if (condition1) ...[
    Widget1(),
    Widget2(),
  ]
else if(condition2)...[
    Widget3(),
    Widget4(),
]
else ...[
    Widget3(),
    Widget4(),
],
1
  • 2
    the multiple widget one t.i.l for me, thanks for this!
    – mochadwi
    Jun 29, 2023 at 13:25
23

You can simply use a conditional statement a==b?c:d

For example :

Container(
  color: Colors.white,
  child: ('condition')
  ? Widget1(...)
  : Widget2(...)
)

I hope you got the idea.

Suppose if there is no else condition you can use a SizedBox.shrink()

Container(
      color: Colors.white,
      child: ('condition')
       ? Widget1(...)
       : SizedBox.shrink()
    )

If it is a column no need to write ?: operator

Column(
 children: <Widget>[
  if('condition')
    Widget1(...),
 ],
)
3
  • 1
    What if there is no else condition? In Columns, saying a==b?c:null will not work
    – cwhisperer
    Apr 16, 2020 at 5:43
  • 1
    You can simply use SizedBox.shrick() as the second widget. updating the answer.
    – Afinas EM
    Apr 16, 2020 at 11:39
  • 3
    If it is a column then you can use if condition directly without else case: `if('condition') widget()'
    – Afinas EM
    Apr 16, 2020 at 11:43
15

Aside from the ternary operator, you can also use Builder widget if you have synchronous operation that needs to be performed before the condition statement.

    Builder(builder: (context) {
      /// some non-async operation here ...
      if(someCondition) {
        return Text('A');
      }
      else {
        return Text('B');
      } 
    })
 
1
  • 1
    Great answer! If you have one if-else condition ternary operator should suffice but if you have multiple if-else if-else conditions or switch cases, the Builder widget should be an appropriate solution.
    – ritz
    Jun 3, 2021 at 16:45
13

Lol after months of using ?: I just find out that I can use this:

Column(
     children: [
       if (true) Text('true') else Text('false'),
     ],
   )
12

Here is the solution. I have fixed it. Here is the code

child: _status(data[index]["status"]),

Widget _status(status) {
  if (status == "3") {
    return Text('Process');
  } else if(status == "1") {
    return Text('Order');
  } else {
    return Text("Waiting");
  }
}
2
  • 1
    How to using it
    – ardi
    Mar 31, 2019 at 6:11
  • I got like 5 different enum to return different widget :D hope I can use switch case :')
    – chichi
    Feb 5, 2023 at 9:57
10

Another alternative: for 'switch's' like statements, with a lot of conditions, I like to use maps:

return Card(
        elevation: 0,
        margin: EdgeInsets.all(1),
        child: conditions(widget.coupon)[widget.coupon.status] ??
            (throw ArgumentError('invalid status')));


conditions(Coupon coupon) => {
      Status.added_new: CheckableCouponTile(coupon.code),
      Status.redeemed: SimpleCouponTile(coupon.code),
      Status.invalid: SimpleCouponTile(coupon.code),
      Status.valid_not_redeemed: SimpleCouponTile(coupon.code),
    };

It's easier to add/remove elements to the condition list without touch the conditional statement.

Another example:

var condts = {
  0: Container(),
  1: Center(),
  2: Row(),
  3: Column(),
  4: Stack(),
};

class WidgetByCondition extends StatelessWidget {
  final int index;
  WidgetByCondition(this.index);
  @override
  Widget build(BuildContext context) {
    return condts[index];
  }
}
8

if you use a list of widgets you can use this:

class HomePage extends StatelessWidget {
  bool notNull(Object o) => o != null;
  @override
  Widget build(BuildContext context) {
    var condition = true;
    return Scaffold(
      appBar: AppBar(
        title: Text("Provider Demo"),
      ),
      body: Center(
          child: Column(
        children: <Widget>[
          condition? Text("True"): null,
          Container(
            height: 300,
            width: MediaQuery.of(context).size.width,
            child: Text("Test")
          )
        ].where(notNull).toList(),
      )),
    );
  }
}
3
  • condition? Text("True"): null, this does an error Asertion false in console, on runtime execution
    – exequielc
    Jul 14, 2019 at 16:57
  • @exequielc you must add .where(notNull).toList() and the end of the WidgetList and the method bool notNull(Object o) => o != null;. Try whole example...
    – otto
    Jul 15, 2019 at 6:42
  • 2
    As of Dart 2.3 to conditionally include a widget in a list you can use: [Text("Hello"), if(world) Text("World")] Jul 26, 2019 at 23:46
6

A better way

 Column(
        children: [
            if (firstCondition == true) ...[
              DayScreen(),
            ] else if(secondCondition == true)...[
              StatsScreen(),
            ], else...[
              StatsScreen(),
            ],
        ],
     ),
5

With a button

bool _paused = false;

CupertinoButton(
  child: _paused ? Text('Play') : Text('Pause'),
  color: Colors.blue,
  onPressed: () {
    setState(() {
      _paused = !_paused;
    });
  },
),
4

****You can also use conditions by using this method** **

 int _moneyCounter = 0;
  void _rainMoney(){
    setState(() {
      _moneyCounter +=  100;
    });
  }

new Expanded(
          child: new Center(
            child: new Text('\$$_moneyCounter', 

            style:new TextStyle(
              color: _moneyCounter > 1000 ? Colors.blue : Colors.amberAccent,
              fontSize: 47,
              fontWeight: FontWeight.w800
            )

            ),
          ) 
        ),
1
  • This is the most clear explanation to using conditions in attributes
    – vin shaba
    Aug 8, 2021 at 23:23
4

EDIT: I no longer recommend the solution I posted below because I realized that using this method, both the child for the true result and the child for the false result are built but only one is used, which unnecessarily slows the code.


PREVIOUS ANSWER:

In my app I created a WidgetChooser widget so I can choose between widgets without conditional logic:

WidgetChooser(
      condition: true,
      trueChild: Text('This widget appears if the condition is true.'),
      falseChild: Text('This widget appears if the condition is false.'),
    );

This is the source for the WidgetChooser widget:

import 'package:flutter/widgets.dart';

class WidgetChooser extends StatelessWidget {
  final bool condition;
  final Widget trueChild;
  final Widget falseChild;

  WidgetChooser({@required this.condition, @required this.trueChild, @required this.falseChild});

  @override
  Widget build(BuildContext context) {
    if (condition) {
      return trueChild;
    } else {
      return falseChild;
    }
  }
}
1
  • Interesting! 👍
    – mahfuz
    Feb 26, 2021 at 10:27
3

This is great article and conversation. I tried to use the ternary operator as described. But the code didn't work resulting in an error as mentioned.

Column(children: [ condition? Text("True"): null,],);

The ternary example above is miss leading. Dart will respond with an error that a null was returned instead of widget. You can't return null. The correct way will be to return a widget:

Column(children: [ condition? Text("True"): Text("false"),],); 

In order for the ternary to work you need to return a Widget. If you don't want to return anything you can return a empty container.

Column(children: [ condition? Text("True"): Container(),],); 

Good luck.

3

You can use ternary operator for conditional statements in dart, It's use is simple

(condition) ? statement1 : statement2

if the condition is true then the statement1 will be executed otherwise statement2.

Taking a practical example

Center(child: condition ? Widget1() : Widget2())

Remember if you are going to use null as Widget2 it is better to use SizedBox.shrink() because some parent widgets will throw an exception after getting a null child.

3

I have no idea whether it's a good practice, but I am using:

class StatmentExample extends StatelessWidget {
  Widget build(BuildContext context) {
    return pageValue==1 ? Page1():pageValue== 2? Page2():pageValue==3 ? Page3():Page4();
  }
}
1
3

I prefer using Map<String, Widget>

Map<String, Widget> pageSelector = {
"login": Text("Login"),
"home": Text("Home"),
}

and inside the build function i pass the key to the map like this

new Center(
 child: pageSelector["here pass the key"] ?? Text("some default widget"),
)

or another solution is to use simple function

Widget conditionalWidget(int numberToCheck){
 switch(numberToCheck){
   case 0: return Text("zero widget");
   case 1: return Text("one widget");
   case 2: return Text("two widget");
   case 3: return Text("three widget");
   default: return Text("default widget");
}

and inside the build function pass the number of widget or any other parameter to check

new Center(
 child: conditionalWidget(pageNumber),
)
3

In my opinion Best and the cleanest way which I prefer is to create an helper typedef function class coditional_widget.dart.

typedef IfWidget = List<Widget> Function(bool, Widget);
typedef IfElseWidget = Widget Function(bool, Widget, Widget);
typedef ElseEmptyWidget = Widget Function(bool, Widget);

IfWidget ifTrueWidget =
    (bool condition, Widget child) => [if (condition) child];

IfElseWidget ifElseWidget =
    (bool condition, Widget isTrueChild, Widget isFalseChild) =>
        condition ? isTrueChild : isFalseChild;

ElseEmptyWidget elseEmptyWidget = (bool condition, Widget isTrueChild) =>
    condition ? isTrueChild : const SizedBox.shrink();

How to use it

// IfWidget 
  ** Row/ Column / Wrap child etc.
   children: <Widget>[
      ...ifWidget(title != null, Text('Only Display for True Conditon')),
      ]

// elseEmptyWidget
  ** Row/ Column / Wrap child etc.
   children: <Widget>[
          
      elseEmptyWidget(title!=null,Text('Only Display for True Conditon')),
      ]



// ifElseWidget
      ** Row/ Column / Wrap child etc.
       children: <Widget>[
            ifElseWidget(true,Text('Only Display for True Conditon'),Text('Only Display for false Conditon')),
          ]

it's only a few you can add more

2

You can use builder in following manning: I have consider a condition where we can get image url as null, hence if null I show a shrink sizedbox as it has no property a completely void widget.

Builder(builder: (BuildContext context) {
  if (iconPath != null) {
    return ImageIcon(
      AssetImage(iconPath!),
      color: AppColors.kPrimaryColor,
    );
  } else {
    return SizedBox.shrink();
  }
})
2

Conditional rendering in Flutter can easily be done by proviso package. It has a comprehensive set of conditional widgets and builders to make a more readable and simpler conditional statement code.

The API & helpers consist of but not limited to:

conditional widgets & builders:

ConditionWidget(
  condition: starred,
  widget: Icon(
    Icons.favorite
  ),
  fallback: fallbackWidget
)

ConditionBuilder(
  condition: (_) => someCondition,
  trueBuilder: (_) => trueWidget,
  fallbackBuilder: (_) => fallbackWidget
)

switch case conditions:

SwitchCaseBuilder.widget<String>(
  context: context,
  condition: (_) => '1',
  caseBuilders: {'1': (_) => someWidget(), '2': (_) => someWidget()},
  fallbackBuilder: (_) => fallbackWidget,
);  

or even a conditional parent widget

ConditionalWrap(
  shouldWrap: shouldWrapChildInParent,
  child: Container(),
  parentBuilder: (child) => Container(
    child: child,
  ),
)

API supports either a single or multiple widgets rendering. You are welcome to give it a try.

2

If you want to avoid using if statements, you can use the Flutter Visibility widget

See the documentation here

1

There are two possibilities :

  1. if you are using one widget only

Solution=>

     Visibility(
       visible: condition == true, 
       child: Text(""),
      ),
    OR

     Offstage(
       offstage: condition == false, 
       child: Text(""),
     ),
  1. if you are using two widgets or more

Solution=>

      bool _visibility = false;
     
      isVisible?
          Widget1 
           :
          WIdget2
1

If you want to use an if statement in a Text() widget, you can use the Anonymous function like so:

class ConditionalStatmentExample extends StatelessWidget {
  Widget build(BuildContext context) {
    return Text(
     (() {
      if(true){
        return "return a string";
      }

      return "any other string when the condition is not met";
     })(),
     textAlign: TextAlign.center, );
  }
}

0
child: Container(
   child: isFile == true ? 
            Image.network(pathfile, width: 300, height: 200, fit: BoxFit.cover) : 
            Text(message.subject.toString(), style: TextStyle(color: Colors.white),
      ),
),
1
  • Please don't post only code as answer, but also provide an explanation what your code does and how it solves the problem of the question. Answers with an explanation are usually more helpful and of better quality, and are more likely to attract upvotes. Jan 23, 2021 at 16:34
0

Do it like this

Widget showIf(bool shouldShow, Widget widget) {
if (shouldShow) {
  return widget;
} else {
  return Container();
}}

So when you want to show something with condition you do like say

Column(children: [showIf(myConditionIsTrue, myComplexWidget)])
0

Flutter Widget to conditionally wrap a subtree with a parent without breaking the code tree

import 'package:flutter/widgets.dart';

/// Conditionally wrap a subtree with a parent widget without breaking the code tree.
///
/// [condition]: the condition depending on which the subtree [child] is wrapped with the parent.
/// [child]: The subtree that should always be build.
/// [conditionalBuilder]: builds the parent with the subtree [child].
///
/// ___________
/// Usage:
/// ```dart
/// return ConditionalParentWidget(
///   condition: shouldIncludeParent,
///   child: Widget1(
///     child: Widget2(
///       child: Widget3(),
///     ),
///   ),
///   conditionalBuilder: (Widget child) => SomeParentWidget(child: child),
///);
/// ```
///
/// ___________
/// Instead of:
/// ```dart
/// Widget child = Widget1(
///   child: Widget2(
///     child: Widget3(),
///   ),
/// );
///
/// return shouldIncludeParent ? SomeParentWidget(child: child) : child;
/// ```
///
class ConditionalParentWidget extends StatelessWidget {
  const ConditionalParentWidget({
    Key key,
    @required this.condition,
    @required this.child,
    @required this.conditionalBuilder,
  }) : super(key: key);

  final Widget child;
  final bool condition;
  final Widget Function(Widget child) conditionalBuilder;

  @override
  Widget build(BuildContext context) {
    return condition ? this.conditionalBuilder(this.child) : this.child;
  }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.