We create Custom Widgets when we choose a customized seem and experience to our app, and we comprehend that there will be a repetition of a precise widget. We can create the customized widget in a new dart file with all the codes and defining the parameters that we want in the constructor.Here we will be discussing an instance of how to construct a easy app through making use of customized property to the widgets and making them separate from their personal properties. We will be making a BMI Calculator App that takes top and weight to calculate the BMI of a person. To exhibit how to use customized widgets we have additionally described positive greater matters on the screen.
Let us start by cleaning up the main.dart file as:
Code:
import 'package:custom_widget_demo/home.dart';
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(
debugShowCheckedModeBanner: false,
title: 'GFG Custom Widget Demo',
theme: ThemeData.dark(),
home: Home(),
);
}
}
As you can see that we have described Home Screen to exhibit all the aspects on the screen. Now as we have cleaned up the primary file we will be growing a widgets listing and add three archives specifically custom_button.dart, custom_column.dart, and custom_container.dart archives to this directory. We will be writing codes for our customized widgets in these files.
Starting with the custom_container.dart file we will be writing the following code:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class CustomContainer extends StatelessWidget {
CustomContainer(
{@required this.child, this.height, this.width, this.onTap, this.color});
final Function onTap;
final Widget child;
final double height;
final double width;
final Color color;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onTap,
child: Container(
height: height,
width: width,
padding: EdgeInsets.all(12),
decoration: BoxDecoration(
color: color, borderRadius: BorderRadius.all(Radius.circular(8))),
child: child,
),
);
}
}
In this customized widget, we have created a Stateless CustomContainer widget which is essentially a container with a rounded nook and an onTap property which we have carried out the usage of the GestureDetector widget. We have described the homes of the widgets as the onTap which accepts a function, a toddler property that accepts a Widget, a height, width, and eventually a colour property. We will see the utilization of this in the Home Widget that we will be described later.
Moving on to our next Custom widget which we define in the custom_button.dart file that is simply a CustomButton widget which we define as follows –
import 'package:flutter/material.dart';
class CustomButton extends StatelessWidget {
CustomButton({this.onTap, this.color = Colors.white30, this.icon});
final Function onTap;
final Color color;
final IconData icon;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onTap,
child: Container(
height: 50,
width: 50,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30), color: color),
child: Icon(icon),
),
);
}
}
We have described clearly a Stateless widget which acts as a easy button that makes use of a GestureDetector to discover the features and additionally accepts an icon as the baby to be displayed interior the button. It is a rounded button with a constant top and width. We can alter the coloration if we want it, however, it already has a customized shade of translucent white.
Coming to our last widget that is simply a CustomColumn which we define in the custom_column.dart file as:
import 'package:flutter/material.dart';
class CustomColumn extends StatelessWidget {
CustomColumn({this.text, this.child});
final String text;
final Widget child;
@override
Widget build(BuildContext context) {
return Column(
children: [
Text(
text,
style: TextStyle(fontSize: 18),
),
child
],
);
}
}
This widget accepts a text and child as its properties displayed in the column.
Now that all the components are ready we are going to write the code that is going to display all of our contents on the screen. All of the code from now on is part of the home.dart file that we define in the lib
import 'package:custom_widget_demo/widgets/custom_button.dart';
import 'package:custom_widget_demo/widgets/custom_column.dart';
import 'package:custom_widget_demo/widgets/custom_container.dart';
import 'package:flutter/material.dart';
import 'dart:math';
enum g { m, f }
We import all of our custom widgets along with material and math.dart files. Apart from these we also created an enum for gender g.
class Home extends StatefulWidget {
@override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
final activeColor = Colors.white30;
final inactiveColor = Colors.white12;
g isSelected;
int height = 160;
int weight = 60;
int age = 25;
String bmi = '';
The Home widget is a stateful widget, and we have all the residences like the activeColor, inactiveColor, the isSelected for gender selection, the height, weight, and son on for BMI calculation.
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('GFG Custom Widget'),
),
body: SafeArea(
child: Container(
padding: EdgeInsets.all(12),
child: Column(
children: [
Row(
children: [
Expanded(
child: CustomContainer(
color: isSelected == g.m ? activeColor : inactiveColor,
onTap: () {
setState(() {
isSelected = g.m;
});
},
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 20.0),
child: Text(
'FEMALE',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 18),
),
),
),
),
SizedBox(
width: 10,
),
Expanded(
child: CustomContainer(
color: isSelected == g.f ? activeColor : inactiveColor,
onTap: () {
setState(() {
isSelected = g.f;
});
},
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 20.0),
child: Text(
'MALE',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 18),
),
),
),
),
],
),
For the first part, we have described a Scaffold underneath which we have described an AppBar and then as a child, we have described SafeArea. Now coming to the aspects we have described a Column that carries all the elements of the screen. The first toddler of the column is a row widget that carries two CustomContainer widgets with an onTap characteristic to choose the gender and trade the coloration of the container as we do so.
SizedBox(
height: 10,
),
CustomContainer(
color: inactiveColor,
height: 100,
child: CustomColumn(
text: 'HEIGHT $height cm',
child: SliderTheme(
data: SliderTheme.of(context).copyWith(
activeTrackColor: Colors.white,
thumbColor: Colors.green,
overlayColor: Color(0x2900ff00),
thumbShape:
RoundSliderThumbShape(enabledThumbRadius: 15.0),
overlayShape:
RoundSliderOverlayShape(overlayRadius: 25.0),
),
child: Slider(
value: height.toDouble(),
min: 120.0,
max: 220.0,
onChanged: (double newValue) {
setState(() {
height = newValue.floor();
});
},
),
),
),
),
After giving some area we have once more described a CustomContainer with the inactive coloration with a CustomColumn which accepts the textual content as Height with dynamically altering heights with the assist of the slider that we defined. We have furnished customized homes to the slider to seem and experience in accordance to our app.
SizedBox(
height: 10,
),
Row(
children: [
Expanded(
child: CustomContainer(
color: inactiveColor,
child: CustomColumn(
text: 'WEIGHT $weight',
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CustomButton(
onTap: () {
setState(() {
weight = weight - 1;
});
},
icon: Icons.arrow_downward,
),
SizedBox(
width: 10,
),
CustomButton(
onTap: () {
setState(() {
weight = weight + 1;
});
},
icon: Icons.arrow_upward,
)
],
),
),
),
),
),
SizedBox(
width: 10,
),
Expanded(
child: CustomContainer(
color: inactiveColor,
child: CustomColumn(
text: 'AGE $age',
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CustomButton(
onTap: () {
setState(() {
age = age - 1;
});
},
icon: Icons.arrow_downward,
),
SizedBox(
width: 10,
),
CustomButton(
onTap: () {
setState(() {
age = age + 1;
});
},
icon: Icons.arrow_upward,
)
],
),
),
),
),
),
],
),
Again After giving some area we described a row with two CustomContainer which each be given a CustomColumn with the textual content as Weight and Age. Both of these containers has two buttons in a row as the infant of the CustomColumn which we define. The performance of these buttons is to expand or limit the price of weight and age.
SizedBox(
height: 10,
),
Row(
children: [
Expanded(
child: CustomContainer(
onTap: () {
setState(() {
bmi = '';
});
},
width: double.infinity,
child: Text(
'CLEAR',
style: TextStyle(
fontSize: 18,
),
textAlign: TextAlign.center,
),
color: activeColor,
),
),
SizedBox(
width: 10,
),
Expanded(
child: CustomContainer(
onTap: () {
double _bmi = weight / pow(height / 100, 2);
setState(() {
bmi = _bmi.toStringAsFixed(1);
});
},
width: double.infinity,
child: Text(
'GET BMI',
style: TextStyle(
fontSize: 18,
),
textAlign: TextAlign.center,
),
color: Colors.green,
),
),
],
),
Here we have described two buttons with the assist of our CustomContainer. The first one is used to clear the output that is displayed and the different one suggests the output on the screen.
SizedBox(
height: 10,
),
Expanded(
child: CustomContainer(
width: double.infinity,
child: Column(
children: [
SizedBox(
height: 20,
),
Text(
'YOUR BMI IS',
style: TextStyle(
fontSize: 18, fontWeight: FontWeight.bold),
),
SizedBox(
height: 20,
),
Text(
bmi,
style: TextStyle(
fontSize: 100, fontWeight: FontWeight.bold),
)
],
),
color: inactiveColor,
),
),
],
),
),
),
);
}
}
The ultimate factor of the App is additionally a CustomContainer which is used to show the calculated BMI on the Screen. This completes our app. Now you can run the app on your device.
Output: