Dynamically show or hide widgets in Flutter

Flutter Jul 21, 2023

In Flutter, you can make your application's user interface more interactive by showing or hiding widgets based on specific conditions. Whether you want to display or hide UI elements in response to user actions, Flutter offers various techniques to achieve this functionality. In this post, we will explore how to dynamically show or hide widgets in your Flutter application, enabling you to create more engaging and flexible user interfaces.

Starting code

We will start with the following code in our main.dart file:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  State createState() => _MyAppState();
}

class _MyAppState extends State {

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Dynamic Widget Demo',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Dynamic Widget Demo'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Container(
                color: Colors.green,
                height: 200,
                width: 200,
              ),
              SizedBox(height: 20),
              ElevatedButton(
                onPressed: () {},
                child: Text('Toggle Widget'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

In this code snippet, we create a simple Flutter application where we have a stateful MyApp widget. Inside our MyApp widget we display a centered column widget with a green Container widget with a height and width of 200, followed by an ElevatedButton widget. At the moment, the button does not have any functionality. However, in the upcoming sections, we will explore how to add dynamic behavior to this button, enabling us to show or hide the green container based on user interactions.

flutter_displaying_green_container_widget_with_toggle_button

1. Conditional rendering

The first approach we will take is called conditional rendering. In the code snippet below we have made some changes to our starting code:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  State createState() => _MyAppState();
}

class _MyAppState extends State {
  bool isVisible = false;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Dynamic Widget Demo',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Dynamic Widget Demo'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              if (isVisible) Container(
                color: Colors.green,
                height: 200,
                width: 200,
              ),
              SizedBox(height: 20),
              ElevatedButton(
                onPressed: () => setState(() => isVisible = !isVisible),
                child: Text('Toggle Widget'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

In the above code snippet, we introduce conditional rendering with an if statement. We use a boolean variable called isVisible to determine whether the Container widget should be shown or hidden. When isVisible is true, the green square is displayed; otherwise, it is hidden.

We achieve the toggle effect by updating the isVisible variable using the setState method when the "Toggle Widget" button is pressed. This triggers a rebuild of the widget tree, reflecting the updated visibility status of the green Container widget.

See the GIF below for the result:

flutter_hiding_green_container_widget_by_clicking_toggle_button

Using curly brackets with an if statement inside the build method to wrap widgets is not allowed because it returns Set<void>, which is not compatible with the expected Widget return type. Luckily in Dart we can omit the curly brackets when we only have one condition as we have done in the above code snippet.

1.1 Replacement widget

In the previous implementation, we completely hide our widget. With conditional rendering, it is also possible to show a replacement widget when the original widget is hidden, see the code below:

isVisible
  ? Container(color: Colors.green, height: 200, width: 200)
  : Container(color: Colors.red, height: 200, width: 200),

In this code snippet, we replaced the if statement with the ternary operator ? : to show the green Container widget when isVisible is true and the red Container widget when isVisible is set to false, see the GIF below:

flutter_switching_between_red_and_green_container_widget_by_clicking_the_toggle_button

2. Using the Visibility widget

In Flutter we also have a dedicated widget to hide widgets. This is the Visibility widget.

The Visibility widget has a required property called visible, which takes a boolean value. If visible is set to true, the child widget will be visible; if it is set to false, the child widget will be hidden.

Other properties of the Visibility widget are:

  1. maintainState: If set to true, the widget's current status will be kept even when it is hidden. If false, the status will reset when hidden.
  2. maintainAnimation: When set to true, any active animations within the widget will continue running even when it is hidden. If false, the animations will stop and reset when hidden.
  3. maintainSize: When true, the widget's size will remain the same when hidden. If false, the widget will have zero size when hidden.
  4. maintainSemantics: If set to true, the accessibility information of the widget will be kept even when it is hidden.
  5. maintainInteractivity: If set to true, the widget will still respond to touch and pointer events even when it is hidden.
  6. replacement: An optional widget to show when the main widget is hidden. It allows you to replace the hidden widget with another one.
  7. child (required): The main widget that will be shown or hidden based on the value of the visible property.

Now that we understand the Visibility widget let us go over some of the possible implementations.

2.1 Completely hidden

To completely hide a widget we can wrap our Container widget with the Visibility widget:

Visibility(
  visible: isVisible,
  child: Container(
    color: Colors.green,
    height: 200,
    width: 200,
  ),
),

In this code snippet, we introduced the Visibility widget that takes our Container widget as a child. We have set the visible property to our isVisible variable. The other functionality remains the same, so when we press the button we will see the following:

flutter_hiding_green_container_widget_by_clicking_toggle_button_using_visibility_widget

2.2 Replacement widget

With the Visibility widget we can also render a replacement widget, see the following code:

Visibility(
  replacement: Container(
    color: Colors.red,
    height: 200,
    width: 200,
  ),
  visible: isVisible,
  child: Container(
    color: Colors.green,
    height: 200,
    width: 200,
  ),
),

In this code snippet, we have added the replacement property to our Visibility widget. This property allows us to specify a replacement widget to display when the main widget is hidden. In our example, we used a red Container widget as the replacement.

flutter_switching_between_red_and_green_container_widget_by_clicking_the_toggle_button_using_the_visibility_widget

Using the replacement property with the Visibility widget achieves the same thing as the conditional rendering approach we used earlier with the ternary operator. However, I find that using the Visibility widget makes the code easier to understand. It provides a simpler way to control widget visibility, making the code clearer and easier to work with.

2.3 Prevent Widget Movement

Previously, when we hid the green Container widget completely, the button would move up because the container's space was removed. To prevent this, we can use additional properties with the Visibility widget:

Visibility(
  maintainSize: true,
  maintainAnimation: true,
  maintainState : true,
  visible: isVisible,
  child: Container(
    color: Colors.green,
    height: 200,
    width: 200,
  ),
),

In this code snippet, we have introduced three properties: maintainSize, maintainAnimation, and maintainState, all set to true. The maintainSize property ensures that the Container widget remains hidden while still occupying its space. The maintainSize property can only be set to true whenever the maintainAnimation and maintainState are also set to true.

flutter_hiding_green_container_while_preventing_the_button_from_moving

3. Changing the color to transparent

Another way to hide our widget is by setting its color property to Colors.transparent. Although this approach may not be used for every widget, it can still be a convenient tool to use in certain scenarios.

Container(
  color: isVisible ? Colors.green : Colors.transparent,
  height: 200,
  width: 200,
),

In this code snippet, we use the isVisible variable to determine the value of the color property. When isVisible is false, we set the color to Colors.transparent, otherwise, it is set to Colors.green.

As you can see in the GIF below this approach also prevents the widgets from moving.

flutter_hiding_green_container_while_preventing_the_button_from_moving_by_setting_color_to_transparent

Conclusion

Flutter offers various methods to dynamically show or hide widgets, allowing you to create more interactive and flexible user interfaces based on changing conditions or user interactions. No matter which method you pick: conditional rendering, the Visibility widget, or color changes. Each approach has its advantages and can be used depending on specific use cases and requirements.

Tags