We will be talking about how to reuse widgets and create custom reusable AppBars in this article.
It’s so easy in flutter. Composing widgets and making it a more powerful and reusable one is so much easy in flutter.
Watch Video Tutorial
Let’s start at one of the wrong ways that beginners used to do.
Let’s say I want some TextFormField in my application and I want it to be of similar look and feel. So there is a tendency of writing methods like this below. Assume that you have a Utils class where we add all the utility methods…
import 'package:flutter/material.dart'; class Utils { // static getTF(TextEditingController controller) { return TextFormField( controller: controller, ); } }
and now to add in the UI….
body: Container( child: Column( children: [ Utils.getTF(_emailController), ...
Well, this definitely works…, but do you see that it doesn’t look like a widget. This is one of the common mistakes that beginners do…
You can customize this function by sending more parameters and thereby customizing the ‘TextFormField’ widget…still this is the wrong way.
Flutter is more powerful to easily handle this..
Let’s see the proper way to do this…
Simply create a dart file with a proper name, such as app_textfield.dart…
then create a class named “AppTextFormField”, this is going to extend a StatelessWidget. This is very important. It is always a good practice to create reusable widgets as StatelessWidgets.
So our AppTextFormField class will look like this.
import 'package:flutter/material.dart'; class AppTextFormField extends StatelessWidget { // AppTextFormField({ this.controller, this.hintText, this.helpText, this.prefixIcon, this.suffixIcon, this.isPassword, this.enabled, this.readOnly, this.borderColor, }); final TextEditingController controller; final String hintText; final String helpText; final IconData prefixIcon; final IconData suffixIcon; final bool isPassword; final bool enabled; final bool readOnly; final Color borderColor; @override Widget build(BuildContext context) { return Container( child: TextFormField( controller: controller, readOnly: null == readOnly ? false : true, obscureText: null == isPassword ? false : true, decoration: InputDecoration( focusedBorder: OutlineInputBorder( borderSide: BorderSide( color: Colors.greenAccent, width: 1.0, ), ), enabledBorder: OutlineInputBorder( borderSide: BorderSide( color: Colors.greenAccent, width: 1.0, ), ), border: OutlineInputBorder( borderSide: BorderSide( color: null == borderColor ? Colors.teal : borderColor, width: 1.0, ), ), hintText: null == hintText ? '' : hintText, helperText: null == helpText ? '' : helpText, prefixIcon: null == prefixIcon ? null : Icon(prefixIcon), suffix: null == suffixIcon ? null : Icon(suffixIcon), enabled: null == enabled ? true : false, ), ), ); } }
Here we are setting all parameters as optional. So we are checking if some are null or not and taking action accordingly.
For eg: if ‘prefixIcon’ is null or not sent as parameter then we will set it to null, then it will disappear from the TextFormField, as simple as it is…
Then in our UI…
Container( child: Column( children: [ AppTextFormField( controller: _emailController, helpText: 'Email', hintText: 'Email', prefixIcon: Icons.email, ), AppTextFormField( controller: _passwordController, helpText: 'Password', hintText: 'Password', isPassword: true, prefixIcon: Icons.lock_open, ), ....
So now, it looks like some widgets are. being added to the Widget tree.
Reusable/Custom AppBar
Creating a reusable AppBar is little different. AppBar extends a PreferredSizeWidget. Yes, it needs a size…
So let’s see in that case how can we create a reusable AppBar.
So Create a new file app_bar.dart and I am gonna name by class IAppBar.
Here, the important thing is we need to supply a height or we will set it to default ‘kToolbarHeight’ from Flutter which is 56.0.
This is how the the whole class will look like…
import 'package:flutter/material.dart'; class IAppBar extends PreferredSize { // final Widget child; final double height; final Color color; IAppBar({ @required this.child, this.color, this.height = kToolbarHeight, }); @override Size get preferredSize => Size.fromHeight(height); @override Widget build(BuildContext context) { return Container( height: preferredSize.height, color: color ?? Colors.red, alignment: Alignment.center, child: child, ); } }
Now using this is as simple as below
return Scaffold( appBar: IAppBar( height: 100, color: Colors.green, child: Column( crossAxisAlignment: CrossAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end, children: [ Text( 'HOME', textAlign: TextAlign.center, style: TextStyle( color: Colors.white, fontSize: 20, ), ), SizedBox( height: 20, ), ], ), ), body: Container( // ), );
The child property can be any widget you send. Here I am sending a Column widget.
That’s it!!!
Source code