How to show/hide widgets programmatically in Flutter

FlutterDartFlutter LayoutFlutter Widget

Flutter Problem Overview


In Android, every single View subclass has a setVisibility() method that allows you modify the visibility of a View object

There are 3 options of setting the visibility:

  • Visible: Renders the View visible inside the layout
  • Invisible: Hides the View, but leaves a gap that is equivalent to what the View would occupy if it were visible
  • Gone: Hides the View, and removes it entirely from the layout. It's as if its height and width were 0dp

Is there something equivalent to the above for Widgets in Flutter?

For a quick reference: https://developer.android.com/reference/android/view/View.html#attr_android:visibility

Flutter Solutions


Solution 1 - Flutter

Definition:

Invisible: The widget takes up physical space on the screen but is not visible to user. This can be achieved using Visibility widget.

Gone: The widget doesn't take up any physical space and is completely gone. This can be achieved using Visibility, if or if-else condition.

Invisible example:
Visibility(
  child: Text("Invisible"),
  maintainSize: true, 
  maintainAnimation: true,
  maintainState: true,
  visible: false, 
),
Gone example:
Visibility(
  child: Text("Gone"),
  visible: false,
),

Using if:
  • For one child:

    Column(
      children: <Widget>[
        Text('Good Morning'), // Always visible
        if (wishOnePerson) Text(' Mr ABC'), // Only visible if condition is true
      ],
    ) 
    
  • For multiple children:

    Column(
      children: [
        Text('Good Morning'), // Always visible
        if (wishAll) ... [ // These children are only visible if condition is true
          Text('Mr ABC'),
          Text('Mr DEF'),
          Text('Mr XYZ'),
        ],
      ],
    )
    
Using if-else:
  • For one child:

    Column(
      children: <Widget>[
        // Only one of them is visible based on 'isMorning' condition
        if (isMorning) Text('Good Morning')
        else Text ('Good Evening'),
      ],
    ) 
    
  • For multiple children:

    Column(
      children: [
        // Only one of the children will be shown based on `beforeSunset` condition
        if (beforeSunset) ... [
          Text('Good morning'),
          Text('Good afternoon'),
        ] else ... [
          Text('Good evening'),
          Text('Good night'),
        ],
      ],
    )
    

Solution 2 - Flutter

UPDATE: Since this answer was written, Visibility was introduced and provides the best solution to this problem.


You can use Opacity with an opacity: of 0.0 to draw make an element hidden but still occupy space.

To make it not occupy space, replace it with an empty Container().

EDIT: To wrap it in an Opacity object, do the following:

            new Opacity(opacity: 0.0, child: new Padding(
              padding: const EdgeInsets.only(
                left: 16.0,
              ),
              child: new Icon(pencil, color: CupertinoColors.activeBlue),
            ))

Google Developers quick tutorial on Opacity: https://youtu.be/9hltevOHQBw

Solution 3 - Flutter

To collaborate with the question and show an example of replacing it with an empty Container().

Here's the example below:

enter image description here

import "package:flutter/material.dart";

void main() {
  runApp(new ControlleApp());
}

class ControlleApp extends StatelessWidget { 
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: "My App",
      home: new HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  @override
  HomePageState createState() => new HomePageState();
}

class HomePageState extends State<HomePage> {
  bool visibilityTag = false;
  bool visibilityObs = false;

  void _changed(bool visibility, String field) {
    setState(() {
      if (field == "tag"){
        visibilityTag = visibility;
      }
      if (field == "obs"){
        visibilityObs = visibility;
      }
    });
  }

  @override
  Widget build(BuildContext context){
    return new Scaffold(
      appBar: new AppBar(backgroundColor: new Color(0xFF26C6DA)),
      body: new ListView(
        children: <Widget>[
          new Container(
            margin: new EdgeInsets.all(20.0),
            child: new FlutterLogo(size: 100.0, colors: Colors.blue),
          ),
          new Container(
            margin: new EdgeInsets.only(left: 16.0, right: 16.0),
            child: new Column(
              children: <Widget>[
                visibilityObs ? new Row(
                  crossAxisAlignment: CrossAxisAlignment.end,
                  children: <Widget>[
                    new Expanded(
                      flex: 11,
                      child: new TextField(
                        maxLines: 1,
                        style: Theme.of(context).textTheme.title,
                        decoration: new InputDecoration(
                          labelText: "Observation",
                          isDense: true
                        ),
                      ),
                    ),
                    new Expanded(
                      flex: 1,
                      child: new IconButton(
                        color: Colors.grey[400],
                        icon: const Icon(Icons.cancel, size: 22.0,),
                        onPressed: () {
                          _changed(false, "obs");
                        },
                      ),
                    ),
                  ],
                ) : new Container(),

                visibilityTag ? new Row(
                  crossAxisAlignment: CrossAxisAlignment.end,
                  children: <Widget>[
                    new Expanded(
                      flex: 11,
                      child: new TextField(
                        maxLines: 1,
                        style: Theme.of(context).textTheme.title,
                        decoration: new InputDecoration(
                          labelText: "Tags",
                          isDense: true
                        ),
                      ),
                    ),
                    new Expanded(
                      flex: 1,
                      child: new IconButton(
                        color: Colors.grey[400],
                        icon: const Icon(Icons.cancel, size: 22.0,),
                        onPressed: () {
                          _changed(false, "tag");
                        },
                      ),
                    ),
                  ],
                ) : new Container(),
              ],
            )
          ),
          new Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              new InkWell(
                onTap: () {
                  visibilityObs ? null : _changed(true, "obs");
                },
                child: new Container(
                  margin: new EdgeInsets.only(top: 16.0),
                  child: new Column(
                    children: <Widget>[
                      new Icon(Icons.comment, color: visibilityObs ? Colors.grey[400] : Colors.grey[600]),
                      new Container(
                        margin: const EdgeInsets.only(top: 8.0),
                        child: new Text(
                          "Observation",
                          style: new TextStyle(
                            fontSize: 12.0,
                            fontWeight: FontWeight.w400,
                            color: visibilityObs ? Colors.grey[400] : Colors.grey[600],
                          ),
                        ),
                      ),
                    ],
                  ),
                )
              ),
              new SizedBox(width: 24.0),
              new InkWell(
                onTap: () {
                  visibilityTag ? null : _changed(true, "tag");
                },
                child: new Container(
                  margin: new EdgeInsets.only(top: 16.0),
                  child: new Column(
                    children: <Widget>[
                      new Icon(Icons.local_offer, color: visibilityTag ? Colors.grey[400] : Colors.grey[600]),
                      new Container(
                        margin: const EdgeInsets.only(top: 8.0),
                        child: new Text(
                          "Tags",
                          style: new TextStyle(
                            fontSize: 12.0,
                            fontWeight: FontWeight.w400,
                            color: visibilityTag ? Colors.grey[400] : Colors.grey[600],
                          ),
                        ),
                      ),
                    ],
                  ),
                )
              ),
            ],
          )                    
        ],
      )
    );
  }
}

Solution 4 - Flutter

Flutter now contains a Visibility Widget that you should use to show/hide widgets. The widget can also be used to switch between 2 widgets by changing the replacement.

This widget can achieve any of the states visible, invisible, gone and a lot more.

    Visibility(
      visible: true //Default is true,
      child: Text('Ndini uya uya'),
      //maintainSize: bool. When true this is equivalent to invisible;
      //replacement: Widget. Defaults to Sizedbox.shrink, 0x0
    ),

Solution 5 - Flutter

Try the Offstage widget

if attribute offstage:true the not occupy the physical space and invisible,

if attribute offstage:false it will occupy the physical space and visible

Offstage(
   offstage: true,
   child: Text("Visible"),
),

Solution 6 - Flutter

You can encapsulate any widget in your code with a new widget called (Visibility), this is from the yellow lamp at the very left side of the widget that you want it to be in-visible

example: say you want to make a row invisible:

  1. Click in the lamp and choose (Wrap with widget)

  2. Rename the widget to Visibility

  3. Add the visible property and set it to false

  4. The Child of the newly created widget (Visibility Widget) is the Widget that you want it to be invisible

              Visibility(
                  visible: false,
                  child: Row(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: <Widget>[
                      SizedBox(
                        width: 10,
                      ),
                      Text("Search",
                        style: TextStyle(fontSize: 20
                        ),),
                    ],
                  ),
                ),
    

I hope it will help someone in the future

Solution 7 - Flutter

bool _visible = false;

 void _toggle() {
    setState(() {
      _visible = !_visible;
    });
  }

onPressed: _toggle,

Visibility(
            visible:_visible,
            child: new Container(
            child: new  Container(
              padding: EdgeInsets.fromLTRB(15.0, 0.0, 15.0, 10.0),
              child: new Material(
                elevation: 10.0,
                borderRadius: BorderRadius.circular(25.0),
                child: new ListTile(
                  leading: new Icon(Icons.search),
                  title: new TextField(
                    controller: controller,
                    decoration: new InputDecoration(
                        hintText: 'Search for brands and products', border: InputBorder.none,),
                    onChanged: onSearchTextChanged,
                  ),
                  trailing: new IconButton(icon: new Icon(Icons.cancel), onPressed: () {
                    controller.clear();
                    onSearchTextChanged('');
                  },),
                ),
              ),
            ),
          ),
          ),

Solution 8 - Flutter

Update

Flutter now has a Visibility widget. To implement your own solution start with the below code.


Make a widget yourself.

show/hide

class ShowWhen extends StatelessWidget {
  final Widget child;
  final bool condition;
  ShowWhen({this.child, this.condition});

  @override
  Widget build(BuildContext context) {
    return Opacity(opacity: this.condition ? 1.0 : 0.0, child: this.child);
  }
}

show/remove

class RenderWhen extends StatelessWidget {
  final Widget child;
  final bool condition;
  RenderWhen({this.child, this.show});

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

By the way, does any one have a better name for the widgets above?

More Reads

  1. Article on how to make a visibility widget.

Solution 9 - Flutter

In flutter 1.5 and Dart 2.3 for visibility gone, You can set the visibility by using an if statement within the collection without having to make use of containers.

e.g

child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
              Text('This is text one'),
              if (_isVisible) Text('can be hidden or shown'), // no dummy container/ternary needed
              Text('This is another text'),
              RaisedButton(child: Text('show/hide'), onPressed: (){
                  setState(() {
                    _isVisible = !_isVisible; 
                  });
              },)
            
          ],
        )

Solution 10 - Flutter

For beginner try this too.

class Visibility extends StatefulWidget {
  @override
  _VisibilityState createState() => _VisibilityState();
}

class _VisibilityState extends State<Visibility> {
  bool a = true;
  String mText = "Press to hide";

  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: "Visibility",
      home: new Scaffold(
          body: new Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              new RaisedButton(
                onPressed: _visibilitymethod, child: new Text(mText),),
                a == true ? new Container(
                width: 300.0,
                height: 300.0,
                color: Colors.red,
              ) : new Container(),
            ],
          )
      ),
    );
  }

  void _visibilitymethod() {
    setState(() {
      if (a) {
        a = false;
        mText = "Press to show";
      } else {
        a = true;
        mText = "Press to hide";
      }
    });
  }
}

Solution 11 - Flutter

As already highlighted by @CopsOnRoad, you can use the Visibility widget. But, if you want to keep its state, for example, if you want to build a viewpager and make a certain button appear and disappear based on the page, you can do it this way

void checkVisibilityButton() {
  setState(() {
  isVisibileNextBtn = indexPage + 1 < pages.length;
  });
}    

 Stack(children: <Widget>[
      PageView.builder(
        itemCount: pages.length,
        onPageChanged: (index) {
          indexPage = index;
          checkVisibilityButton();
        },
        itemBuilder: (context, index) {
          return pages[index];
        },
        controller: controller,
      ),
      Container(
        alignment: Alignment.bottomCenter,
        child: Row(
          mainAxisAlignment: MainAxisAlignment.end,
          children: <Widget>[
            Visibility(
              visible: isVisibileNextBtn,
              child: "your widget"
            )
          ],
        ),
      )
    ]))

Solution 12 - Flutter

IMHO, there's no need in visibility property or special widget for that in Flutter cause if you don't need a widget displayed - just don't add it to widget tree OR replace it with an empty widget:

  @override
  Widget build(BuildContext context) {
    return someFlag ? Text('Here I am') : SizedBox();
  }

I think the reason for Visibility widget existance is because so many people asked:) People are used to having visibility of elements controled by some property

Solution 13 - Flutter

There are quite a few different ways to achieve this in Flutter. Before I explain each one of them, I'll first provide quick solutions equivalent to the Android-native "invisible" and "gone":

View.INVISIBLE:

Opacity(
  opacity: 0.0,
  child: ...
)

View.GONE:

Offstage(
  child: ...
)

Now let's compare these and other methods:

Opacity

This widget sets the opacity (alpha) to anything you want. Setting it to 0.0 is just slightly less visible than setting it to 0.1, so hopefully that's easy to understand. The widget will still maintain its size and occupy the same space, and maintain every state, including animations. Since it leaves a gap behind, users can still touch it or click it. (BTW, if you don't want people to touch an invisible button, you can wrap it with an IgnorePointer widget.)

Offstage

This widget hides the child widget. You can imagine it as putting the widget "outside of the screen" so users won't see it. The widget still goes through everything in the flutter pipeline, until it arrives at the final "painting" stage, where it doesn't paint anything at all. This means it will maintain all the state and animations, but just won't render anything on the screen. In addition, it also won't occupy any space during layout, leaving no gap behind, and naturally users cannot click it.

Visibility

This widget combines the above (and more) for your convenience. It has parameters like maintainState, maintainAnimation, maintainSize, maintainInteractivity etc. Depending on how you set those properties, it decides from the following:

  1. if you want to maintain state, it will either wrap the child with an Opacity or with an Offstage, depends on whether you also want to maintain size. Further, unless you want to maintainInteractivity, it will also wrap an IgnorePointer for you, because clicking on a transparent button is kinda weird.

  2. if you don't want to maintainState at all, it directly replaces the child with a SizedBox so it's completely gone. You can change the blank SizedBox to anything you want, with the replacement property.

Removing Widget

If you don't need to maintain states and etc, it's usually recommended to completely remove the widget from the tree. For example, you can use if (condition) to decide whether to include a widget in a list, or use condition ? child : SizedBox() to replace it with a SizedBox directly. This avoid unnecessary calculations and is the best for performance.

Solution 14 - Flutter

Conditionally add/remove a widget

To include/exclude a widget:

if (this.isLuckyTime) TextButton(
 child: Text('I am feeling lucky')
)

In case you want to make the widget invisible but still keep its size then wrap it into <Visibility> and set maintainSize: true. If it's stateful and you need to keep it's state then also add maintainState: true.

Animated Widget fade in and fade out

To make the widget fade in and out smoothly you can use AnimatedOpacity.

AnimatedOpacity(
   opacity: this.isLuckyTime ? 1.0 : 0.0,
   duration: Duration(milliseconds: 500),
   child: Text('I am feeling lucky')
)

Specifically for devs coming from native android: it's probably worth mentioning that you never show/hide widgets, you redraw the UI with or without the widgets you need:

Introduction to declarative UI
State Management
Simple app state management

Solution 15 - Flutter

class VisibilityExample extends StatefulWidget {
  const VisibilityExample({Key? key}) : super(key: key);

  @override
  _VisibilityExampleState createState() => _VisibilityExampleState();
}

class _VisibilityExampleState extends State<VisibilityExample> {
  bool visible = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Lines'),
      ),
      body: Container(
        color: Colors.black87,
        child: Stack(alignment: Alignment.bottomCenter, children: [
          ListView(
            shrinkWrap: true,
            children: [
              Container(
                height: 200,
              ),
              InkWell(
                onTap: () {},
                onHover: (value) {
                  print(value);
                  setState(() {
                    visible = !visible;
                  });
                },
                child: Visibility(
                  maintainSize: true,
                  maintainAnimation: true,
                  maintainState: true,
                  visible: visible,
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      IconButton(
                        color: Colors.white54,
                        icon: const Icon(
                          Icons.arrow_left_outlined,
                        ),
                        onPressed: () {},
                      ),
                      const SizedBox(
                        width: 5,
                      ),
                      IconButton(
                        color: Colors.white54,
                        icon: const Icon(
                          Icons.add_circle_outlined,
                        ),
                        onPressed: () {},
                      ),
                      const SizedBox(
                        width: 5,
                      ),
                      IconButton(
                        color: Colors.white54,
                        icon: const Icon(
                          Icons.remove_circle,
                        ),
                        onPressed: () {},
                      ),
                      const SizedBox(
                        width: 5,
                      ),
                      IconButton(
                        color: Colors.white54,
                        icon: const Icon(
                          Icons.arrow_right_outlined,
                        ),
                        onPressed: () {},
                      ),
                      const SizedBox(
                        width: 5,
                      ),
                      IconButton(
                        color: Colors.white54,
                        icon: const Icon(Icons.replay_circle_filled_outlined),
                        onPressed: () {},
                      ),
                    ],
                  ),
                ),
              ),
            ],
          ),
        ]),
      ),
    );
  }
}
 

enter image description here

Solution 16 - Flutter

Maybe you can use the Navigator function like this Navigator.of(context).pop();

Solution 17 - Flutter

One solution is to set tis widget color property to Colors.transparent. For instance:

IconButton(
    icon: Image.asset("myImage.png",
        color: Colors.transparent,
    ),
    onPressed: () {},
),

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser3217522View Question on Stackoverflow
Solution 1 - FlutterCopsOnRoadView Answer on Stackoverflow
Solution 2 - FlutterCollin JacksonView Answer on Stackoverflow
Solution 3 - Flutterrafaelcb21View Answer on Stackoverflow
Solution 4 - FlutterEdmore M Gonese DigolodollarzView Answer on Stackoverflow
Solution 5 - FlutterMobile Team ADR-FlutterView Answer on Stackoverflow
Solution 6 - FlutterMohammed H. HannoushView Answer on Stackoverflow
Solution 7 - FlutterAlan JohnView Answer on Stackoverflow
Solution 8 - FlutterAmsakannaView Answer on Stackoverflow
Solution 9 - FlutternonybrightoView Answer on Stackoverflow
Solution 10 - FlutterHitesh DanidhariyaView Answer on Stackoverflow
Solution 11 - FlutterAlexPadView Answer on Stackoverflow
Solution 12 - FlutterMaxim SaplinView Answer on Stackoverflow
Solution 13 - Flutteruser1032613View Answer on Stackoverflow
Solution 14 - FlutterccpizzaView Answer on Stackoverflow
Solution 15 - FlutterX PersPectiveView Answer on Stackoverflow
Solution 16 - FlutterOnkar NirhaliView Answer on Stackoverflow
Solution 17 - FlutteredmondView Answer on Stackoverflow