Show user-friendly error page instead of exception in Flutter

Official docs:

When an error occurs during the build phase, the ErrorWidget.builder callback is invoked to build the widget that is used instead of the one that failed. By default, in debug mode this shows an error message in red, and in release mode this shows a gray background.

You can define it in the builder method of the MaterialApp widget.

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class CustomError extends StatelessWidget {
  final FlutterErrorDetails errorDetails;

  const CustomError({
    Key key,
    @required this.errorDetails,
  })  : assert(errorDetails != null),
        super(key: key);

  @override
  Widget build(BuildContext context) {
    return Card(
      child: Padding(
        child: Text(
          "Something is not right here...",
          style: const TextStyle(
            color: Colors.white,
            fontWeight: FontWeight.bold,
          ),
        ),
        padding: const EdgeInsets.all(8.0),
      ),
      color: Colors.red,
      margin: EdgeInsets.zero,
    );
  }
}

class MyApp extends StatelessWidget {
  MyApp({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      builder: (BuildContext context, Widget widget) {
        ErrorWidget.builder = (FlutterErrorDetails errorDetails) {
          return CustomError(errorDetails: errorDetails);
        };

        return widget;
      },
      title: 'Flutter Demo',
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  MyHomePage({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: ListView(
        children: <Widget>[
          Text(
            'Welcome,',
            style: Theme.of(context).textTheme.headline6,
          ),
          FirstName(),
        ],
        padding: const EdgeInsets.all(30.0),
      ),
    );
  }
}

class FirstName extends StatelessWidget {
  FirstName({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Text(null);
  }
}

This is how it looks:

Before and after (click to enlarge)


Building on Spectarion's answer:

  1. Added Scaffold. Without Scaffold the message appears on top of previously rendered content.
  2. Moved more code to the helper method.

Code:

void setErrorBuilder() {
  ErrorWidget.builder = (FlutterErrorDetails errorDetails) {
    return Scaffold(
        body: Center(
            child: Text("Unexpected error. See console for details.")));
  };
} 

class MyApp extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
     setErrorBuilder();

     return MaterialApp(
       builder: (BuildContext context, Widget widget) {
         setErrorBuilder();    
         return widget;
       },
       title: 'Flutter Demo',
       home: MyHomePage(title: 'Flutter Demo Home Page'),
     );
   }
 }

Tags:

Dart

Flutter