Builder Classes in Dart
Before understanding builder classes, let us understand about Flutter that makes the best use of the builder classes. Flutter is actually not a programming language, it is a software development kit (SDK) that has some in-built macros, customizable and read-to-use widgets as well as libraries and tools that can be deployed while creating cross-platform mobile applications.
In Flutter, to create a new widget we use a ' build ' widget associated with that particular widget and the framework passes the BuildContext parameter to it.
' Build ' Widget ( BuildContext context ) :
In Flutter, other than the build widget there isn't any other widget that needs the context parameter in their constructors or functions. Therefore, the context parameter has to be passed through the build widget only, otherwise there will be more than one call to the build function. To accomplish this, we make use of the ' Builder ' class that creates the child and returns it. This Builder class passes a comtext to the child. This child acts as a custom build function.
Builder class constructor :
Builder( { key key, @required WidgetBuilder builder } ) //
this creates a widget that delegates its build to a callback.
It is mandatory to not keep the argument null.
Builder class Methods
The various methods associated with the builder class are :
- build( BuildContext context ) -> Widget
- createElement( ) -> StatelessElement
- debugDescribeChildren( ) -> List< DiagnosticsNode >
- debugFillProperties( DiagnosticPropertiesBuilder properties ) -> void
- noSuchMethod( Invocation invocation ) -> dynamic
- toString( { DiagnosticLevel minLevel : DiagnosticLevel.info } ) -> String
- toStringDeep( { String prefixLineOne = '', String? prefixOtherLines, DiagnosticLevel minLevel = DiagnosticLevel.debug } ) -> String
- toStringShallow( { String joiner = ', ', DiagnosticLevel minLevel = DiagnosticLevel.debug } ) -> String
- toStringShort( ) -> String
Let us consider the following example in Dart that explains the concept of the Builder class. To increase the understandability of this concept, we will be making a simple mobile application. This will app will only have a main page containing scaffold with an AppBar and a button which when tapped display a message.
Example :
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 : ' Builder App Demo ' ,
debugShowCheckedModeBanner : false ,
theme: ThemeData (
primarySwatch : Colors.green ,
) ,
home : Home( ) ,
) ;
}
}
class Home extends StatelessWidget
{
@override
Widget build( BuildContext context )
{
return Scaffold (
// appbar
appBar : AppBar (
title : Text( ' Assert Tutorial ' ) ,
) ,
// detect gesture
body : Center (
child : GestureDetector (
onTap : ( ) {
Scaffold.of( context ).showSnackBar (
new SnackBar (
content : new Text( ' This is an assert Tutorial ' ) ,
) ,
) ;
} ,
// box styling
Child : Container (
margin : EdgeInsets.all( 18 ) ,
height : 40 ,
decoration : BoxDecoration (
color : Colors.blueAccent ,
borderRadius : BorderRadius.circular( 8 ) ,
) ,
child : Center (
child : Text (
' CLICK HERE ' ,
style :
TextStyle( fontWeight : FontWeight.bold, color : Colors.white ) ,
) ,
) ,
) ,
) ,
) ,
) ;
}
}
Output :
However, this code resulted in an error because the same context is being passed to the Scaffold and the SnackBar widget. The content being passed as a parameter to the Scaffold does not actually belong to it. So, the app gives the following error.
======== Exception caught by gesture ===============================================================
The following assertion was thrown while handling a gesture:
Scaffold.of() called with a context that does not contain a Scaffold.
No Scaffold ancestor could be found starting from the context that was passed to Scaffold.of(). This usually happens when the context provided is
from the same StatefulWidget as that whose build function actually creates the Scaffold widget being sought.
However, on tapping the button ‘ CLICK HERE ’ the following output is being displayed :
On tapping the button one time, following output was displayed :
Handler: "onTap"
Recognizer: TapGestureRecognizer#3ed06
debugOwner: GestureDetector
state: possible
won arena
finalPosition: Offset(826.4, 387.2)
finalLocalPosition: Offset(826.4, 38.4)
button: 1
sent tap down
====================================================================================================
We have tried to resolve the error of the above code in the following program. Consider another example :
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 : ' Builder Demo ' ,
debugShowCheckedModeBanner : false ,
theme : ThemeData (
primarySwatch : Colors.green ,
) ,
home : Home( ) ,
) ;
}
}
class Home extends StatelessWidget {
@override
Widget build( BuildContext context ) {
return Scaffold (
// appbar
appBar : AppBar (
title : Text( ' Assert Statement ' ) ,
) ,
// detect gesture
body : Center (
child : Builder ( builder : ( BuildContext context ) {
return GestureDetector (
onTap : ( ) {
Scaffold.of( context ).showSnackBar (
new SnackBar (
content : new Text( ' This is the Dart Tutorial ' ) ,
) ,
) ;
} ,
child : Container (
margin: EdgeInsets.all( 18 ) ,
height : 40 ,
decoration : BoxDecoration (
color : Colors.blueGrey ,
borderRadius : BorderRadius.circular( 8 ) ,
) ,
child : Center (
child : Text (
' CLICK ME ' ,
style : TextStyle (
fontWeight : FontWeight.bold, color : Colors.white ) ,
) ,
) ,
) ,
) ;
} ) ,
) ,
) ;
} }
Output on Console :
Launching lib\main.dart on Edge in debug mode...
Waiting for connection from debug service on Edge...
This app is linked to the debug service: ws://127.0.0.1:58278/aWUVHjHPR3o=/ws
Debug service listening on ws://127.0.0.1:58278/aWUVHjHPR3o=/ws
Running with sound null safety
Debug service listening on ws://127.0.0.1:58278/aWUVHjHPR3o=/ws
Output on the simulator web app:
Some of its properties are :
- Builder -> WidgetBuilder // called to obtain the child widget
- hashCode -> int // obtains the hash code for the object it is invoked for
- key -> Key? // controls the replacing of one widget by the other
- runtimeType -> Type // represents the object of the runtime type