How to present an empty view in flutter?

Flutter

Flutter Problem Overview


How to present an empty view in flutter as Widget.build cannot return null to indicate that there is nothing to render.

Flutter Solutions


Solution 1 - Flutter

For anyone like me who was wondering what is "the correct way" to show an empty widget - official Material codebase uses this:

Widget build(BuildContext context) {
  return SizedBox.shrink();
}

SizedBox.shrink() is a widget that is unlike Container or Material has no background or any decorations whatsoever. It sizes itself to the smallest area possible, if not influenced by parent constraints.

Solution 2 - Flutter

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      
    );
  }
}

You can also simply return an empty Container and avoid using the Scaffold entirely. But this would result in a black screen if this is the only primary widget in you app, you can set the color property of the Container if you want to prevent the black background.

Example:

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.white // This is optional
    );
  }
}

Solution 3 - Flutter

There are many possible solutions of it. Like

    Widget build(context) => Container();
    Widget build(context) => SizedBox();
  1.  Widget build(context) => Scaffold();
    

Solution 4 - Flutter

Performance

Container = 166,173 ms

SizedBox.shrink = 164,523 ms

DIY

main() async {
  testWidgets('test', (WidgetTester tester) async {
    await tester.pumpWidget( Container());
    final Stopwatch timer = new Stopwatch()..start();
    for (int index = 0; index < 5000000; index += 1) {
      await tester.pump();
    }
    timer.stop();
    debugPrint('Time taken: ${timer.elapsedMilliseconds}ms');
  });
}

Solution 5 - Flutter

When a build function returns null, the error message from flutter is :

> Build functions must never return null. To return an empty space that causes the building widget to fill available room, return "new Container()". To return an empty space that takes as little room as possible, return "new Container(width: 0.0, height: 0.0)".

Solution 6 - Flutter

This may be too late but all of these solutions are not suitable in some scenarios like playing with PopupMenuItems or affecting UI rendering!

Null safety Update

  [
    .
    .
    .
    if(condition)...[//Conditionally widget(s) here
      Something(...),
    ],
    .
    .
    .
],

The solution is to remove null items before pass to the rendering component:

Column(
  children: [
    Text('Title'),
    name != '' 
      ? Text(name) //show name
      : null // just pass a null we will filter it in next line!
  ].where((e) => e != null).toList()// Filter list and make it List again!
)

in this way, we can have a lot of null and UI will not affect by any empty Widget.

PopupMenuButton example where we cannot pass SizedBox :

PopupMenuButton(
    icon: Icon(Icons.add),
    itemBuilder: (context) => [
        PopupMenuItem(
            child: Row(children:[ Icon(Icons.folder), Text('So something')]),
            value: 'do.something',
        ),
        1 > 2 //⚠️ A false condition
        ? PopupMenuItem(
           child: Row(children: [ Icon(Icons.file_upload), Text('⚠️No way to display 😎')]),
            'no.way.to.display',
          )
        : null,// ⚠️ Passing null
        PopupMenuItem(
           child: Row(children: [ Icon(Icons.file_upload), Text('Do something else')]),
            'do.something.else',
        )
    ].where((e) => e != null).toList(),//ℹ️ Removing null items  
    onSelected: (item) {}
)

And this can be used as API with extension:

extension NotNulls on List {
  ///Returns items that are not null, for UI Widgets/PopupMenuItems etc.
  notNulls() {
    return where((e) => e != null).toList();
  }
}

//Usage:
PopupMenuButton(
    icon: Icon(Icons.add),
    itemBuilder: (context) => [
        PopupMenuItem(
            child: Row(children:[ Icon(Icons.folder), Text('So something')]),
            value: 'do.something',
        ),
        1 > 2 //⚠️ A false condition
        ? PopupMenuItem(
           child: Row(children: [ Icon(Icons.file_upload), Text('⚠️No way to display 😎')]),
            'no.way.to.display',
          )
        : null,// ⚠️ Passing null
        PopupMenuItem(
           child: Row(children: [ Icon(Icons.file_upload), Text('Do something else')]),
            'do.something.else',
        )
    ].notNulls(),//ℹ️ Removing null items  
    onSelected: (item) {}
)


Solution 7 - Flutter

The recommended widget to show nothing is to use SizedBox.

SizedBox(
  width: 200.0,
  height: 300.0,
)

Solution 8 - Flutter

My problem was very similar, but I found Container and SizedBox.shrink still affect the UI (frustratingly).

The best solution I've got is to build it differently using a named constructor and initializer list. An example of these would be:

class MyWidget extends StatelessWidget {
    final String name = 'Default';
    final bool hasThing = true;

    MyWidget({this.name});

    MyWidget.withoutThing({this.name}) : hasThing = false;

    @override
    Widget build(BuildContext context) {
        //define widgets they have in common here (as many as possible)
        if (hasThing) {
            return Widget(child: Thing(this.name));
        } else {
            return Widget(child: WithoutThing(this.name));
        }
    }
}

And to use it:

Center(child: MyWidget.withoutThing(name: 'Foo'),)//don't show thing

or

Center(child: MyWidget(name: 'Foo'),)

based on your needs.

For more on initializer lists: https://stackoverflow.com/questions/50274605/colon-after-constructor-in-dart

Solution 9 - Flutter

Inside Column I am using SizedBox(height: 0.01)

Column(
  children: [
    Text('Title'),
    name == ''
    ? SizedBox(height: 0.01) // show nothing
    : Text(name) // show name
  ]
)

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
QuestionlextView Question on Stackoverflow
Solution 1 - FlutterGeorgeView Answer on Stackoverflow
Solution 2 - FlutterRahul MahadikView Answer on Stackoverflow
Solution 3 - FlutterCopsOnRoadView Answer on Stackoverflow
Solution 4 - FlutterRoddy RView Answer on Stackoverflow
Solution 5 - FlutterTheDrevView Answer on Stackoverflow
Solution 6 - FlutterMamrezoView Answer on Stackoverflow
Solution 7 - FlutterAawaz GyawaliView Answer on Stackoverflow
Solution 8 - FlutterLukeView Answer on Stackoverflow
Solution 9 - FluttermahfuzView Answer on Stackoverflow