183
votes

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

15

15 Answers

113
votes

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

290
votes

Invisible: The widget takes physical space on the screen but not visible to user.

Gone: The widget doesn't take any physical space and is completely gone.


Invisible example

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

Gone example

Visibility(
  child: Text("Gone"),
  visible: false,
),

You can also use if or if-else.

  • Using if

    Column(
      children: <Widget>[
        Text('Good Morning'), // Always visible
        if (hasName) Text(' Mr ABC'), // Visible only if 'hasName' is true
      ],
    ) 
    
  • Using if-else

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

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],
                          ),
                        ),
                      ),
                    ],
                  ),
                )
              ),
            ],
          )                    
        ],
      )
    );
  }
}
35
votes

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
    ),
27
votes

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"),
),
14
votes

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

10
votes
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('');
                  },),
                ),
              ),
            ),
          ),
          ),
9
votes

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; 
                  });
              },)

          ],
        )
9
votes

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.
6
votes

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"
            )
          ],
        ),
      )
    ]))
5
votes

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";
      }
    });
  }
}
5
votes

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

1
votes

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

-1
votes

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

-8
votes

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

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