- We mainly use themes for sharing the colors and fonts styles throughout the app.
- Flutter uses the default theme while creating an application.
- If we want to share a custom theme to the entire application, we need to use a ThemeData under the MateialApp() widget.
Read the Documentation in
main.dart
import 'package:flutter/material.dart';
void main() => runApp(BMICalculator());
class BMICalculator extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
// TODO Setting Default Theme
// theme: ThemeData.dark()
// TODO copyWith automatically selects accent and textTheme according to the dark theme
theme: ThemeData.dark().copyWith(
primaryColor: Color(0xFF0A0E21), // Actionbar color
scaffoldBackgroundColor: Color(0xFF0A0E21), //body color
),
// TODO alternative way for setting Theme Data
// ThemeData(
// primaryColor: Color(0xFF0A0E21), // Actionbar color
// scaffoldBackgroundColor: Color(0xFF0A0E21), //body color
// accentColor: Colors.purple,
// textTheme: TextTheme(
// bodyText1: TextStyle(color: Color(0xFF0A0E21)),
// ) // Floating Button color
// ),
home: InputPage(),
);
}
}
class InputPage extends StatefulWidget {
@override
_InputPageState createState() => _InputPageState();
}
class _InputPageState extends State<InputPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('BMI CALCULATOR'),
),
body: Center(
child: Text('Body Text'),
),
floatingActionButton: Theme(
// data: ThemeData.light(), //alternative way for setting theme
data: ThemeData(accentColor: Colors.purple),
// Setting custom Theme for Floating Button
child: FloatingActionButton(
child: Icon(Icons.add),
),
),
);
}
}pubspec.yaml
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^0.1.2
font_awesome_flutter: ^8.4.0- It’s always good practice to use Reusable Widgets to maintain consistency throughout the app.
- When we are dealing with multiple projects, we don’t like to write to each code multiple times.
- It will create duplication and in the end, if any issue comes we end up with a mess.
- So, the best way is to create a base widget and use it everywhere.
main.dart
import 'package:flutter/material.dart';
import 'input_page.dart';
void main() => runApp(BMICalculator());
class BMICalculator extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
primaryColor: Color(0xFF0A0E21), // Actionbar color
scaffoldBackgroundColor: Color(0xFF0A0E21), //body color
),
home: InputPage(),
);
}
}input_page.dart
import 'package:flutter/material.dart';
class InputPage extends StatefulWidget {
@override
_InputPageState createState() => _InputPageState();
}
class _InputPageState extends State<InputPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('BMI CALCULATOR'),
),
body: Column(
children: <Widget>[
Expanded(
child: Row(
children: <Widget>[
Expanded(
child: ReusableCard(
colour: Color(0xFF1D1E33),
),
),
Expanded(
child: ReusableCard(
colour: Color(0xFF1D1E33),
),
),
],
),
),
Expanded(
child: ReusableCard(
colour: Color(0xFF1D1E33),
),
),
Expanded(
child: Row(
children: <Widget>[
Expanded(
child: ReusableCard(
colour: Color(0xFF1D1E33),
),
),
Expanded(
child: ReusableCard(
colour: Color(0xFF1D1E33),
),
),
],
),
),
],
));
}
}
class ReusableCard extends StatelessWidget {
ReusableCard({@required this.colour});
final Color colour;
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.all(15.0),
decoration: BoxDecoration(
color: colour, borderRadius: BorderRadius.circular(10.0)),
);
}
}pubspec.yaml
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^0.1.2
font_awesome_flutter: ^8.4.0- If you never intend to change a variable then we have to declare using the keyword final or const.
- The final variable can be set only once.
- The const variable is a compile-time constant.(Const variables are implicitly final.)
Example
void main() {
const int myCount = 3;
final mDate = DateTime.now();
print(myCount);
print(mDate);
}input_page.dart
import 'package:flutter/material.dart';
const bottomContainerHeight = 80.0;
const activeCardColor = Color(0xFF1D1E33);
const bottomContainerColor = Color(0xFFEB1555);
class InputPage extends StatefulWidget {
@override
_InputPageState createState() => _InputPageState();
}
class _InputPageState extends State<InputPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('BMI CALCULATOR'),
),
body: Column(
children: <Widget>[
Expanded(
child: Row(
children: <Widget>[
Expanded(
child: ReusableCard(
colour: activeCardColor,
),
),
Expanded(
child: ReusableCard(
colour: activeCardColor,
),
),
],
),
),
Expanded(
child: ReusableCard(
colour: activeCardColor,
),
),
Expanded(
child: Row(
children: <Widget>[
Expanded(
child: ReusableCard(
colour: activeCardColor,
),
),
Expanded(
child: ReusableCard(
colour: activeCardColor,
),
),
],
),
),
Container(
color: bottomContainerColor,
margin: EdgeInsets.only(top: 10.0),
width: double.infinity,
height: bottomContainerHeight,
)
],
));
}
}
class ReusableCard extends StatelessWidget {
ReusableCard({@required this.colour});
final Color colour;
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.all(15.0),
decoration: BoxDecoration(
color: colour, borderRadius: BorderRadius.circular(10.0)),
);
}
}- Build a custom widget by composing smaller widgets (instead of extending them).
- It is somewhat similar to implementing a custom ViewGroup in Android, where all the building blocks are already existing, but you provide a different behavior—for example, custom layout logic.
main.dart
import 'package:flutter/material.dart';
import 'input_page.dart';
void main() => runApp(BMICalculator());
class BMICalculator extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
primaryColor: Color(0xFF0A0E21), // Actionbar color
scaffoldBackgroundColor: Color(0xFF0A0E21), //body color
),
home: InputPage(),
);
}
}input_page.dart
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'reusable_card.dart';
import 'icon_content.dart';
const bottomContainerHeight = 80.0;
const activeCardColor = Color(0xFF1D1E33);
const bottomContainerColor = Color(0xFFEB1555);
class InputPage extends StatefulWidget {
@override
_InputPageState createState() => _InputPageState();
}
class _InputPageState extends State<InputPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('BMI CALCULATOR'),
),
body: Column(
children: <Widget>[
Expanded(
child: Row(
children: <Widget>[
Expanded(
child: ReusableCard(
colour: activeCardColor,
cardChild: IconContent(
icon: FontAwesomeIcons.mars,
label: 'MALE',
),
),
),
Expanded(
child: ReusableCard(
colour: activeCardColor,
cardChild: IconContent(
icon: FontAwesomeIcons.venus,
label: 'FEMALE',
),
),
),
],
),
),
Expanded(
child: ReusableCard(
colour: activeCardColor,
),
),
Expanded(
child: Row(
children: <Widget>[
Expanded(
child: ReusableCard(
colour: activeCardColor,
),
),
Expanded(
child: ReusableCard(
colour: activeCardColor,
),
),
],
),
),
Container(
color: bottomContainerColor,
margin: EdgeInsets.only(top: 10.0),
width: double.infinity,
height: bottomContainerHeight,
)
],
));
}
}input_content.dart
import 'package:flutter/material.dart';
const labelTextStyle = TextStyle(
fontSize: 18.0,
color: Color(0xFF8D8E98),
);
class IconContent extends StatelessWidget {
IconContent({this.icon, this.label});
final IconData icon;
final String label;
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
icon,
size: 80.0,
),
SizedBox(
height: 15.0,
),
Text(label, style: labelTextStyle)
],
);
}
}reusable_card.dart
import 'package:flutter/material.dart';
class ReusableCard extends StatelessWidget {
ReusableCard({@required this.colour, this.cardChild});
final Color colour;
final Widget cardChild;
@override
Widget build(BuildContext context) {
return Container(
child: cardChild,
margin: EdgeInsets.all(15.0),
decoration: BoxDecoration(
color: colour, borderRadius: BorderRadius.circular(10.0)),
);
}
}- Gestures are generally defined as any physical action / movement of a user in the intention of activating a specific control of the mobile device.
- In other words, Gestures are as simple as tapping the screen of the mobile device to do actions.
input_page.dart
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'reusable_card.dart';
import 'icon_content.dart';
const bottomContainerHeight = 80.0;
const activeCardColor = Color(0xFF1D1E33);
const bottomContainerColor = Color(0xFFEB1555);
const inactiveCardColor = Color(0xFF111328);
class InputPage extends StatefulWidget {
@override
_InputPageState createState() => _InputPageState();
}
class _InputPageState extends State<InputPage> {
Color maleCardColour = inactiveCardColor;
Color femaleCardColour = inactiveCardColor;
void updateColour(int gender) {
if (gender == 1) {
if (maleCardColour == inactiveCardColor) {
maleCardColour = activeCardColor;
femaleCardColour = inactiveCardColor;
} else {
maleCardColour = inactiveCardColor;
}
}
if (gender == 2) {
if (femaleCardColour == inactiveCardColor) {
femaleCardColour = activeCardColor;
maleCardColour = inactiveCardColor;
} else {
femaleCardColour = inactiveCardColor;
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('BMI CALCULATOR'),
),
body: Column(
children: <Widget>[
Expanded(
child: Row(
children: <Widget>[
Expanded(
child: GestureDetector(
onTap: () {
setState(() {
updateColour(1);
});
},
child: ReusableCard(
colour: maleCardColour,
cardChild: IconContent(
icon: FontAwesomeIcons.mars,
label: 'MALE',
),
),
),
),
Expanded(
child: GestureDetector(
onTap: () {
setState(() {
updateColour(2);
});
},
child: ReusableCard(
colour: femaleCardColour,
cardChild: IconContent(
icon: FontAwesomeIcons.venus,
label: 'FEMALE',
),
),
),
),
],
),
),
Expanded(
child: ReusableCard(
colour: activeCardColor,
),
),
Expanded(
child: Row(
children: <Widget>[
Expanded(
child: ReusableCard(
colour: activeCardColor,
),
),
Expanded(
child: ReusableCard(
colour: activeCardColor,
),
),
],
),
),
Container(
color: bottomContainerColor,
margin: EdgeInsets.only(top: 10.0),
width: double.infinity,
height: bottomContainerHeight,
)
],
));
}
}- Enum or enumeration is used for defining named constant values and an enumerated type is declared using the enum keyword.
- For more refer, https://github.com/Gowtham-app-developer/Android-Interview-Questions/blob/main/Core%20Java.md#enum-in-java
enum EnumName { typeA, typeB, typeC }
EnumName.typeAExample
void main() {
// Car car = Car(carStyle: 2);
Car car = Car(carStyle: CarType.SUV);
print(car.carStyle);
}
class Car {
// int carStyle;
CarType carStyle;
Car({this.carStyle});
}
enum CarType {
hatchback,
SUV,
convertible,
coupe,
}input_page.dart
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'reusable_card.dart';
import 'icon_content.dart';
const bottomContainerHeight = 80.0;
const activeCardColor = Color(0xFF1D1E33);
const bottomContainerColor = Color(0xFFEB1555);
const inactiveCardColor = Color(0xFF111328);
enum Gender { male, female }
class InputPage extends StatefulWidget {
@override
_InputPageState createState() => _InputPageState();
}
class _InputPageState extends State<InputPage> {
Color maleCardColour = inactiveCardColor;
Color femaleCardColour = inactiveCardColor;
void updateColour(Gender selectedGender) {
if (selectedGender == Gender.male) {
if (maleCardColour == inactiveCardColor) {
maleCardColour = activeCardColor;
femaleCardColour = inactiveCardColor;
} else {
maleCardColour = inactiveCardColor;
}
}
if (selectedGender == Gender.female) {
if (femaleCardColour == inactiveCardColor) {
femaleCardColour = activeCardColor;
maleCardColour = inactiveCardColor;
} else {
femaleCardColour = inactiveCardColor;
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('BMI CALCULATOR'),
),
body: Column(
children: <Widget>[
Expanded(
child: Row(
children: <Widget>[
Expanded(
child: GestureDetector(
onTap: () {
setState(() {
updateColour(Gender.male);
});
},
child: ReusableCard(
colour: maleCardColour,
cardChild: IconContent(
icon: FontAwesomeIcons.mars,
label: 'MALE',
),
),
),
),
Expanded(
child: GestureDetector(
onTap: () {
setState(() {
updateColour(Gender.female);
});
},
child: ReusableCard(
colour: femaleCardColour,
cardChild: IconContent(
icon: FontAwesomeIcons.venus,
label: 'FEMALE',
),
),
),
),
],
),
),
Expanded(
child: ReusableCard(
colour: activeCardColor,
),
),
Expanded(
child: Row(
children: <Widget>[
Expanded(
child: ReusableCard(
colour: activeCardColor,
),
),
Expanded(
child: ReusableCard(
colour: activeCardColor,
),
),
],
),
),
Container(
color: bottomContainerColor,
margin: EdgeInsets.only(top: 10.0),
width: double.infinity,
height: bottomContainerHeight,
)
],
));
}
}- A ternary operator evaluates the test condition and executes a block of code based on the result of the condition.
syntax
condition ? expression1 : expression2;if(condition is true)
{ Do this if true} else { Do this if false}condition ? Do this if true : Do this if falseExample
void main() {
bool jackIsAwesome = true;
if(jackIsAwesome) {
print('True');
} else {
print('False');
}
// using Ternary Operator
// jackIsAwesome == true ? print('True') : print('False');
jackIsAwesome ? print('True') : print('False');
int myAge = 10;
bool eligibleForVote = myAge > 18 ? true : false;
print(eligibleForVote);
}input_page.dart
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'reusable_card.dart';
import 'icon_content.dart';
const bottomContainerHeight = 80.0;
const activeCardColor = Color(0xFF1D1E33);
const bottomContainerColor = Color(0xFFEB1555);
const inactiveCardColor = Color(0xFF111328);
enum Gender { male, female }
class InputPage extends StatefulWidget {
@override
_InputPageState createState() => _InputPageState();
}
class _InputPageState extends State<InputPage> {
Gender selectedGender;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('BMI CALCULATOR'),
),
body: Column(
children: <Widget>[
Expanded(
child: Row(
children: <Widget>[
Expanded(
child: GestureDetector(
onTap: () {
setState(() {
selectedGender = Gender.male;
});
},
child: ReusableCard(
colour: selectedGender == Gender.male ? activeCardColor : inactiveCardColor,
cardChild: IconContent(
icon: FontAwesomeIcons.mars,
label: 'MALE',
),
),
),
),
Expanded(
child: GestureDetector(
onTap: () {
setState(() {
selectedGender = Gender.female;
});
},
child: ReusableCard(
colour: selectedGender == Gender.female ? activeCardColor : inactiveCardColor,
cardChild: IconContent(
icon: FontAwesomeIcons.venus,
label: 'FEMALE',
),
),
),
),
],
),
),
Expanded(
child: ReusableCard(
colour: activeCardColor,
),
),
Expanded(
child: Row(
children: <Widget>[
Expanded(
child: ReusableCard(
colour: activeCardColor,
),
),
Expanded(
child: ReusableCard(
colour: activeCardColor,
),
),
],
),
),
Container(
color: bottomContainerColor,
margin: EdgeInsets.only(top: 10.0),
width: double.infinity,
height: bottomContainerHeight,
)
],
));
}
}- Functions are first-class objects in Dart and can be passed as parameters to other functions.
- We pass a function to a widget essentially saying, invoke this function when something happens.
- Callbacks using interfaces like Android have too much boilerplate code for a simple callback.
Example 1
void main() {
// int result = add(3,5);
int result = calculator (5, 8, add);
print(result);
}
// int calculator(int n1, int n2, Function calculation) {
// return calculation (n1, n2);
// }
Function calculator = (int n1, int n2, Function calculation){
return calculation (n1, n2);
};
int add(int n1, int n2){
return n1 + n2;
}
int multiply(int n1, int n2){
return n1 * n2;
}Example 2
void main() {
Car myCar = Car (drive: slowDrive);
print(myCar.drive);
myCar.drive();
myCar.drive = fastDrive;
myCar.drive();
}
class Car {
Car({this.drive});
Function drive;
}
void slowDrive(){
print('Slow Driving');
}
void fastDrive(){
print('Fast Driving');
}input_page.dart
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'reusable_card.dart';
import 'icon_content.dart';
const bottomContainerHeight = 80.0;
const activeCardColor = Color(0xFF1D1E33);
const bottomContainerColor = Color(0xFFEB1555);
const inactiveCardColor = Color(0xFF111328);
enum Gender { male, female }
class InputPage extends StatefulWidget {
@override
_InputPageState createState() => _InputPageState();
}
class _InputPageState extends State<InputPage> {
Gender selectedGender;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('BMI CALCULATOR'),
),
body: Column(
children: <Widget>[
Expanded(
child: Row(
children: <Widget>[
Expanded(
child: ReusableCard(
onPress: () {
setState(() {
selectedGender = Gender.male;
});
},
colour: selectedGender == Gender.male
? activeCardColor
: inactiveCardColor,
cardChild: IconContent(
icon: FontAwesomeIcons.mars,
label: 'MALE',
),
),
),
Expanded(
child: ReusableCard(
onPress: () {
setState(() {
selectedGender = Gender.female;
});
},
colour: selectedGender == Gender.female
? activeCardColor
: inactiveCardColor,
cardChild: IconContent(
icon: FontAwesomeIcons.venus,
label: 'FEMALE',
),
),
),
],
),
),
Expanded(
child: ReusableCard(
colour: activeCardColor,
),
),
Expanded(
child: Row(
children: <Widget>[
Expanded(
child: ReusableCard(
colour: activeCardColor,
),
),
Expanded(
child: ReusableCard(
colour: activeCardColor,
),
),
],
),
),
Container(
color: bottomContainerColor,
margin: EdgeInsets.only(top: 10.0),
width: double.infinity,
height: bottomContainerHeight,
)
],
));
}
}reusable_card.dart
import 'package:flutter/material.dart';
class ReusableCard extends StatelessWidget {
ReusableCard({@required this.colour, this.cardChild, this.onPress});
final Color colour;
final Widget cardChild;
final Function onPress;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onPress,
child: Container(
child: cardChild,
margin: EdgeInsets.all(15.0),
decoration: BoxDecoration(
color: colour,
borderRadius: BorderRadius.circular(10.0),
),
),
);
}
}
- In Flutter, we can customize slider widgets with themes.
- For more visit, https://api.flutter.dev/flutter/material/SliderThemeData-class.html
input_page.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'reusable_card.dart';
import 'icon_content.dart';
import 'constants.dart';
enum Gender { male, female }
int height = 180;
class InputPage extends StatefulWidget {
@override
_InputPageState createState() => _InputPageState();
}
class _InputPageState extends State<InputPage> {
Gender selectedGender;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('BMI CALCULATOR'),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
child: Row(
children: <Widget>[
Expanded(
child: ReusableCard(
onPress: () {
setState(() {
selectedGender = Gender.male;
});
},
colour: selectedGender == Gender.male
? kActiveCardColor
: kInactiveCardColor,
cardChild: IconContent(
icon: FontAwesomeIcons.mars,
label: 'MALE',
),
),
),
Expanded(
child: ReusableCard(
onPress: () {
setState(() {
selectedGender = Gender.female;
});
},
colour: selectedGender == Gender.female
? kActiveCardColor
: kInactiveCardColor,
cardChild: IconContent(
icon: FontAwesomeIcons.venus,
label: 'FEMALE',
),
),
),
],
),
),
Expanded(
child: ReusableCard(
colour: kActiveCardColor,
cardChild: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'HEIGHT',
style: kLabelTextStyle,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.alphabetic,
children: [
Text(
height.toString(),
style: kNumberTextStyle,
),
Text(
'cm',
style: kLabelTextStyle,
),
],
),
SliderTheme(
data: SliderTheme.of(context).copyWith(
activeTrackColor: Colors.white,
inactiveTrackColor: Color(0xFF8D8E98),
thumbColor: Color(0xFFEB1555),
overlayColor: Color(0x15EB1555),
thumbShape:
RoundSliderThumbShape(enabledThumbRadius: 15.0),
overlayShape:
RoundSliderOverlayShape(overlayRadius: 30.0),
),
child: Slider(
value: height.toDouble(),
min: 120.0,
max: 220.0,
// activeColor: Color(0xFFEB1555),
// inactiveColor: Color(0xFF8D8E98),
onChanged: (double newValue) {
setState(() {
height = newValue.round();
});
},
),
)
],
),
),
),
Expanded(
child: Row(
children: <Widget>[
Expanded(
child: ReusableCard(
colour: kActiveCardColor,
),
),
Expanded(
child: ReusableCard(
colour: kActiveCardColor,
),
),
],
),
),
Container(
color: kBottomContainerColor,
margin: EdgeInsets.only(top: 10.0),
width: double.infinity,
height: kBottomContainerHeight,
)
],
));
}
}constants.dart
import 'package:flutter/material.dart';
const kBottomContainerHeight = 80.0;
const kActiveCardColor = Color(0xFF1D1E33);
const kBottomContainerColor = Color(0xFFEB1555);
const kInactiveCardColor = Color(0xFF111328);
const kLabelTextStyle = TextStyle(
fontSize: 18.0,
color: Color(0xFF8D8E98),
);
const kNumberTextStyle = TextStyle(
fontSize: 50.0,
fontWeight: FontWeight.w900,
);icon_content.dart
import 'package:flutter/material.dart';
import 'constants.dart';
class IconContent extends StatelessWidget {
IconContent({this.icon, this.label});
final IconData icon;
final String label;
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
icon,
size: 80.0,
),
SizedBox(
height: 15.0,
),
Text(label, style: kLabelTextStyle)
],
);
}
}- In flutter it faovors composition over inheritance for building widgets.
- If we want to try and build things from scratch from the simplest widgets possible and that way flutter can keep our component's performance and keep our app fast.
- Composing widgets -> If we take a basic widget such as a container, it's actually composed of smaller widgets.
- By combining these simple widgets together, we can buils a more complex widgets.
input_page.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'reusable_card.dart';
import 'icon_content.dart';
import 'constants.dart';
enum Gender { male, female }
class InputPage extends StatefulWidget {
@override
_InputPageState createState() => _InputPageState();
}
class _InputPageState extends State<InputPage> {
Gender selectedGender;
int height = 180;
int weight = 60;
int age = 20;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('BMI CALCULATOR'),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
child: Row(
children: <Widget>[
Expanded(
child: ReusableCard(
onPress: () {
setState(() {
selectedGender = Gender.male;
});
},
colour: selectedGender == Gender.male
? kActiveCardColor
: kInactiveCardColor,
cardChild: IconContent(
icon: FontAwesomeIcons.mars,
label: 'MALE',
),
),
),
Expanded(
child: ReusableCard(
onPress: () {
setState(() {
selectedGender = Gender.female;
});
},
colour: selectedGender == Gender.female
? kActiveCardColor
: kInactiveCardColor,
cardChild: IconContent(
icon: FontAwesomeIcons.venus,
label: 'FEMALE',
),
),
),
],
),
),
Expanded(
child: ReusableCard(
colour: kActiveCardColor,
cardChild: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'HEIGHT',
style: kLabelTextStyle,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.alphabetic,
children: [
Text(
height.toString(),
style: kNumberTextStyle,
),
Text(
'cm',
style: kLabelTextStyle,
),
],
),
SliderTheme(
data: SliderTheme.of(context).copyWith(
activeTrackColor: Colors.white,
inactiveTrackColor: Color(0xFF8D8E98),
thumbColor: Color(0xFFEB1555),
overlayColor: Color(0x15EB1555),
thumbShape:
RoundSliderThumbShape(enabledThumbRadius: 15.0),
overlayShape:
RoundSliderOverlayShape(overlayRadius: 30.0),
),
child: Slider(
value: height.toDouble(),
min: 120.0,
max: 220.0,
// activeColor: Color(0xFFEB1555),
// inactiveColor: Color(0xFF8D8E98),
onChanged: (double newValue) {
setState(() {
height = newValue.round();
});
},
),
)
],
),
),
),
Expanded(
child: Row(
children: <Widget>[
Expanded(
child: ReusableCard(
colour: kActiveCardColor,
cardChild: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'WEIGHT',
style: kLabelTextStyle,
),
Text(
weight.toString(),
style: kNumberTextStyle,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
RoundIconButton(
icon: FontAwesomeIcons.minus,
onPressed: () {
setState(() {
weight--;
});
},
),
SizedBox(
width: 10.0,
),
RoundIconButton(
icon: FontAwesomeIcons.plus,
onPressed: () {
setState(() {
weight++;
});
},
),
],
),
],
),
),
),
Expanded(
child: ReusableCard(
colour: kActiveCardColor,
cardChild: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'AGE',
style: kLabelTextStyle,
),
Text(
age.toString(),
style: kNumberTextStyle,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
RoundIconButton(
icon: FontAwesomeIcons.minus,
onPressed: () {
setState(() {
age--;
});
},
),
SizedBox(
width: 10.0,
),
RoundIconButton(
icon: FontAwesomeIcons.plus,
onPressed: () {
setState(() {
age++;
});
},
),
],
),
],
),
),
),
],
),
),
Container(
color: kBottomContainerColor,
margin: EdgeInsets.only(top: 10.0),
width: double.infinity,
height: kBottomContainerHeight,
)
],
));
}
}
class RoundIconButton extends StatelessWidget {
RoundIconButton({@required this.icon, @required this.onPressed});
final IconData icon;
final Function onPressed;
@override
Widget build(BuildContext context) {
return RawMaterialButton(
child: Icon(icon),
onPressed: onPressed,
elevation: 6.0,
constraints: BoxConstraints.tightFor(
width: 56.0,
height: 56.0,
),
shape: CircleBorder(),
fillColor: Color(0xFF4C4F5E),
);
}
}- Navigation and routing are some of the core concepts of all mobile application, which allows the user to move between different pages.
- In Flutter, the screens and pages are known as routes, and these routes are just a widget.
- In Android, a route is similar to an Activity, whereas, in iOS, it is equivalent to a ViewController.
- In any mobile app, navigating to different pages defines the workflow of the application, and the way to handle the navigation is known as routing.
- Flutter provides a basic routing class MaterialPageRoute and two methods Navigator.push() and Navigator.pop() that shows how to navigate between two routes.
Read the Documentation in
input_page.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'reusable_card.dart';
import 'icon_content.dart';
import 'constants.dart';
import 'results_page.dart';
enum Gender { male, female }
class InputPage extends StatefulWidget {
@override
_InputPageState createState() => _InputPageState();
}
class _InputPageState extends State<InputPage> {
Gender selectedGender;
int height = 180;
int weight = 60;
int age = 20;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('BMI CALCULATOR'),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
child: Row(
children: <Widget>[
Expanded(
child: ReusableCard(
onPress: () {
setState(() {
selectedGender = Gender.male;
});
},
colour: selectedGender == Gender.male
? kActiveCardColor
: kInactiveCardColor,
cardChild: IconContent(
icon: FontAwesomeIcons.mars,
label: 'MALE',
),
),
),
Expanded(
child: ReusableCard(
onPress: () {
setState(() {
selectedGender = Gender.female;
});
},
colour: selectedGender == Gender.female
? kActiveCardColor
: kInactiveCardColor,
cardChild: IconContent(
icon: FontAwesomeIcons.venus,
label: 'FEMALE',
),
),
),
],
),
),
Expanded(
child: ReusableCard(
colour: kActiveCardColor,
cardChild: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'HEIGHT',
style: kLabelTextStyle,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.alphabetic,
children: [
Text(
height.toString(),
style: kNumberTextStyle,
),
Text(
'cm',
style: kLabelTextStyle,
),
],
),
SliderTheme(
data: SliderTheme.of(context).copyWith(
activeTrackColor: Colors.white,
inactiveTrackColor: Color(0xFF8D8E98),
thumbColor: Color(0xFFEB1555),
overlayColor: Color(0x15EB1555),
thumbShape:
RoundSliderThumbShape(enabledThumbRadius: 15.0),
overlayShape:
RoundSliderOverlayShape(overlayRadius: 30.0),
),
child: Slider(
value: height.toDouble(),
min: 120.0,
max: 220.0,
// activeColor: Color(0xFFEB1555),
// inactiveColor: Color(0xFF8D8E98),
onChanged: (double newValue) {
setState(() {
height = newValue.round();
});
},
),
)
],
),
),
),
Expanded(
child: Row(
children: <Widget>[
Expanded(
child: ReusableCard(
colour: kActiveCardColor,
cardChild: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'WEIGHT',
style: kLabelTextStyle,
),
Text(
weight.toString(),
style: kNumberTextStyle,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
RoundIconButton(
icon: FontAwesomeIcons.minus,
onPressed: () {
setState(() {
weight--;
});
},
),
SizedBox(
width: 10.0,
),
RoundIconButton(
icon: FontAwesomeIcons.plus,
onPressed: () {
setState(() {
weight++;
});
},
),
],
),
],
),
),
),
Expanded(
child: ReusableCard(
colour: kActiveCardColor,
cardChild: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'AGE',
style: kLabelTextStyle,
),
Text(
age.toString(),
style: kNumberTextStyle,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
RoundIconButton(
icon: FontAwesomeIcons.minus,
onPressed: () {
setState(() {
age--;
});
},
),
SizedBox(
width: 10.0,
),
RoundIconButton(
icon: FontAwesomeIcons.plus,
onPressed: () {
setState(() {
age++;
});
},
),
],
),
],
),
),
),
],
),
),
GestureDetector(
onTap: () {
Navigator.push(context, MaterialPageRoute(builder: (context) {
return ResultsPage();
}));
},
child: Container(
child: Text('CALCULATE'),
color: kBottomContainerColor,
margin: EdgeInsets.only(top: 10.0),
width: double.infinity,
height: kBottomContainerHeight,
),
)
],
));
}
}
class RoundIconButton extends StatelessWidget {
RoundIconButton({@required this.icon, @required this.onPressed});
final IconData icon;
final Function onPressed;
@override
Widget build(BuildContext context) {
return RawMaterialButton(
child: Icon(icon),
onPressed: onPressed,
elevation: 6.0,
constraints: BoxConstraints.tightFor(
width: 56.0,
height: 56.0,
),
shape: CircleBorder(),
fillColor: Color(0xFF4C4F5E),
);
}
}results_page.dart
import 'package:flutter/material.dart';
class ResultsPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('BMI CALCULATOR'),
),
body: Text('Hello World'),
);
}
}- Dart Map is an object that stores data in the form of a key-value pair.
- Each value is associated with its key, and it is used to access its corresponding value.
- Both keys and values can be any type. In Dart Map, each key must be unique, but the same value can occur multiple times.
Syntax
Map<KeyType, ValueType> mapName {
Key: Value
}
mapName[Key]Example
Map<String, int> phoneBook = {
'Android': 99998888,
'Flutter': 99998888,
'IOS': 99998888,
};
main(){
print(phoneBook['Android']);
phoneBook['Android'] = 888888888;
print(phoneBook['Android']);
print(phoneBook.length);
print(phoneBook.keys);
print(phoneBook.values);
}