Flutter Apprentice Notes Part 2
Flutter Apprentice Notes Part 2
Navigator is like stack which store no of routes to the pages with their respective
address on the application and to create that routes in materialApp
return MaterialApp(
title: _title,
initialRoute: '/',
routes: {
'/': (context) {
return MyHomePage();
},
'/page1': (context) {
return Page1('Page 1');
},
'/page2': (context) {
return Page2('Page 2');
},
'/page3': (context) {
return Page3('Page 3');
},
},
);
//Below body text must be inside stateless widget or stateful widget i
have taken it just for the sake of simplicity
body: Center(
child: ElevatedButton(
child: Text('Page 1'),
onPressed: () => Navigator.pushNamed(context, '/page2'),
),
),
1. List<int> ListofNumbers = [for (var num = 0; num < 15; num++) num]; this
code will create a list contain numbers from 1-15.
Checkboxes vs Switch: Both CheckBox and Switch have the same implementation.
Checkbox(
activeColor: Colors.amber,
checkColor: Colors.green,
value: isChecked,
onChanged: (bool? value) {
setState(() {
isChecked = value!;
});
},
)
isChecked is a bool variable which is initilized with false value. The onChanged will take
that isChecked value as parameter and then inside setState we have set the value of
isChecked true(value contain false but with ! symbol it will convert that true value to
false).
Container:
container taking space as much as possible if it's have no children you can find out by
taking empty container within scaffold widget and make change it's color and you will
see that it takes the whole screen but if we take a child within container then it takes only
the space assign to that widget e.g. Text class.
If we want center the container then we can simply put a whole container into a center
widget this will make it goes to center and if we want to customise it with different
values from different size then we should use margin property.
If we have only one child in contain then we should consider the center class according to
flutter docs.
body: Container(
margin: EdgeInsets.all(63),
height: 155,
width: 155,
padding: EdgeInsets.all(24),
1. Creating you own widget: we can create our own widget by creating a new dart file
and there we will create a class and then we can use that class name as widget in our
other dart files in the same project folder.
2. Function with and without parenthesis: Function without parenthesis mean it will
not execute immediately when app is running it will wait until someone press the
button and function with parenthesis will execute immediately.
answers(changeIt()),
3. Binding a function to a variable lambda function:
bottomNavigationBar: Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.red),
),
child: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
currentIndex: index,
onTap: (value) {
setState(() {
index = value;
});
},
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.ac_unit_outlined), label: 'School'),
BottomNavigationBarItem(
icon: Icon(Icons.car_rental), label: 'School'),
BottomNavigationBarItem(
icon: Icon(Icons.unfold_less), label: 'School'),
BottomNavigationBarItem(icon: Icon(Icons.error), label:
'School'),
],
),
),
1. Pro Tip: if your PC is slow then you should consider the physical device emulator so
that rendering of the app done by phone. appicon.co website is used to create your
own icon.
2. Image Class:
Image(
image: AssetImage('images/asad.png'),
fit: BoxFit.fitWidth,
),
1. FittedBox: Creates a widget that scales and positions its child within itself according
to fit.
Expanded(
child: FittedBox(
fit: BoxFit.contain,
child: FlutterLogo(),
))
1. Flexible vs Expanded: Flexible widget takes only the required space while Expanded
widget takes the availaable space. Below flex property will expand the widget upto 3
time bigger than the next Flexible widget.
FlexFit.loose
FlexFit.tight
Forces the widget to fill all of its extra space.
Flexible(
flex: 3,
fit: FlexFit.tight,
child: Container(
height: 150.0,
width: 150.0,
color: Colors.pink,
alignment: Alignment.center,
child: Text('Container 1'),
),
),
if we have to build screen like this then we should use card property here for the line
between card title is divider which is used to divide two widget
SizedBox(
width: 255,
child: Divider(
color: Colors.white70,
thickness: 2.0,
),
),
1. Pro Tip: some time cloning app from github are not null safety so we check it by
command dart pub outdated --mode=null-safety for upgrading packages to null
safety dart pub upgrade --null-safety
2. Image.assets(''): Image.asset is a named constructor which derives from Image
class.
Center vs Align class: Center class lets you center it's child within itself. while align
class lets you move around it's child on various dimension unlike center class. if we
have single widget to center then center widget is more suitable for that but if we
want our widget to move around on the page then Align widget is best for that.
return Align(
alignment: Alignment.bottomRight,
child: Container(
child: Image.asset(
'images/dice1.png',
scale: 3,
),
),
);
'MaterialStateProperty<Color> error giving while setting background color of text
button
child: TextButton(
style: ButtonStyle(backgroundColor: Colors.accents),
// Instead of the above we can write like below
ButtonStyle(
backgroundColor:
MaterialStateProperty.all(Colors.yellow)),
TextButton(
child: Text('Example'),
onPressed: () {},
style: TextButton.styleFrom(backgroundColor: Colors.red),
)
1. Pro Tip: When we hot reload the app only call the build method if something
change inside the build method flutter will update the state of widget tree and their
corresponding element tree but if you change something outside build method then
we have to restart the app.
2. setState() method: setState method basically call the build method to rebuild and
check for any change if exists.
3. BuildContext: buildContext is the reference to the widget location in a widget tree
when it's executed it called the widget which or at the top of this method like
MaterialApp in most cases. every widget have it's own context which let's that
widget chain it with it's parent widget. Widget build(BuildContext context)
{ return MaterialApp(
Navigator.push(), Navigator.pop():
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondRoute()),
);
Navigator.push method will push the route to the stack which are maintains by Navigator
and below MaterialPageRoute will gives us the initial material class animation while
routing from one screen to another which in this case is route. Above the first context is
refers to the build method of current file or it's just the reference for current page from
where we navigate to the second screen. For coming back to Second screen we need pop
function which actually pop out the route from stack with the help of Navigator. Below
context will call this method when this widget is inserted into widget tree. This is
platform specifi animation style to navigate to the second screen but if you want to create
your own routes then we can use NamedRoute like below and we will place this code
inside the materialApp class and will definitly remove the home property from that file
becasue the initial routes define the home location. This we can put multiple routes to the
same app. but if we have only two routes then we should use MaterialPageRoute. Below
routes is taking Maps which store keys and it's value.
return MaterialApp(
initialRoute: '/',
routes: {
'/': (context) => InputPage(),
'/second': (context) => FirstRoute(),
'/third': (context) => SecondRoute()
},
//if you want to navigate to the second screen from first screen then
put the below code inside onPressed
Navigator.pushNamed(context, '/second');
child: ElevatedButton(
onPressed: () {
Navigator.pop(context);
},
Cookbook
ColorScheme in themeData: A set of twelve colors based on the Material spec that can
be used to configure the color properties of most components.
1. If theme brightness is light, use primary color.
2. If theme brightness is dark, use surface color.
For examples:
Light Mode
Set brightness to light, then set primary to yellow and onPrimary to black, and set all
other colors to grey to showcase that they are not relevant to AppBar:
Dark Mode Set brightness to dark, then set surface to yellow and onSurface to black, and
set all other colors to grey to showcase that they are not relevant to AppBar like the given
example below.
theme: ThemeData(
colorScheme: const ColorScheme.dark(
primary: Colors.grey,
primaryVariant: Colors.grey,
secondary: Colors.green,
secondaryVariant: Colors.grey,
surface: Colors.amber,
background: Colors.grey,
error: Colors.grey,
onPrimary: Colors.grey,
onSecondary: Colors.grey,
onSurface: Colors.black,
onBackground: Colors.grey,
onError: Colors.grey,
brightness: Brightness.dark)),
Slider vs RangeSlider: The only difference b/w both is rangeSlider let us select the
subset from the range values.
SliderTheme(
data: SliderTheme.of(context).copyWith(
activeTrackColor: Colors.white,
inactiveTrackColor: Colors.grey,
thumbColor: Color(0xffeb1555),
thumbShape:
RoundSliderThumbShape(enabledThumbRadius: 15.0),
overlayColor: Color(0x600eb1555),
),
child: Slider(
value: height,
label: '${height.round()}',
onChanged: (double newValueGivenBySlider) {
setState(() {
height = newValueGivenBySlider;
});
},
divisions: 220,
min: 120.0,
max: 220.0,
),
),
//Same is the RangeSlider but here you have to initilize RangeValues
variable like below not above the slider but above the
// build method where we initilize most of our variable.
RangeValues rangeValues = RangeValues(120.0, 220.0);
RangeSlider(
divisions: 220,
min: 0,
max: 220.0,
labels:
RangeLabels(rangeValues.start.round().toString(),
rangeValues.end.round().toString()),
values: rangeValues,
onChanged: (values) {
setState(
() {
rangeValues = values;
},
);
},
)
Different types of FloatingActionButton:
1. FloatingActionButton.extended
2. FloatingActionButton.large
3. FloatingActionButton.small
4. RawMaterialButton()
Also flutter team has said that if you want to create multiple floatingactionbutton on the
same screen then we should consider the heroTag to distinguise them all. or we can use
RawMaterialButton also. RawMaterialButton method is used to create the floating action
button from scratch for further explanation go deeper as i explain in below steps.
RawMaterialButton(
onPressed: () {},
// shape: RoundedRectangleBorder(borderRadius:
BorderRadius.circular(220.0)),
shape: CircleBorder(),
child: Icon(icon),
fillColor: kFabButtonColor,
constraints: BoxConstraints().tighten(
width: 56.9,
height: 56.9,
),
);
1. Pro Tip: if we want a floating button or something else to be our liking then we
should go dip deeper into that button by clicking on that widget with pressing
control button this will take us to the documentaion writtern by flutter team for that
widget where further we have to check the build method of that widget which
determine how the widget has been build by team. Also if you want a variable to
change like using slider then declare that variable in state class which is inherited
from statefulWidget class. In dart it doesn't matter if you keep a variable name as
keyword.
2. Container Gradient styling:
3. Container(
4. height: 144.0,
5. width: 144.0,
6. decoration: BoxDecoration(
7. gradient: LinearGradient(
8. begin: Alignment.topLeft,
9. end: Alignment.topRight,
10. colors: const [
11. Colors.red,
12. Colors.pink,
13. Colors.purple,
14. ],
15. ),
16. ),
17. )
18. async , await, Future: async is used to let the app work in the background and also
it will let the app run other programs and will not wait for program having async.
asynchronus operation lets our others programs to complete until it's done
synchronus operation lets our others programs to stops until it's done await
keyword is used when we downloading or accessing something from internet which
most of the time is a time consuming so we tells to the app using await keyword that
wait untill data download from internet. Future creates a delay and will finish the
computaion first within the specified duration. Future represents a potential result,
one that might not have been computed yet.
o To define an async function, add async before the function body:
o The await keyword works only in async functions.
19. Future task2() async { // async will asynchronize the task2 to
complete others
20. Duration threeSecond = Duration(seconds: 3);
21. String result;
22. await Future.delayed(threeSecond, () {
23. result = 'task 2 data';
24. print('Task 2 complete');
25. });
26. return result;
27. }
28. Pro Tip: compileSdkVersion defines which Android SDK version will be used by
gradle to compile your app. targetSdkVersion is a property that tells the system for
which Android version the app was designed and tested on.
Pro Tips:
1. Ctrl + shift + B will give you the options of building the app to which specific
platform. e.g. android, IOS, web, macOs.
2. Some of pub.dev packages have the indication of (flutter favourite) which
determine the most suitable package in that type of work for which you are
looking.
3. If you have message says deprecated version embeding problem then you
should add meta data tag into androidManefest.xml file under application
<meta-data android:name="flutterEmbedding"
android:value="2" />
1. initState(), deactivate() methods: initstate and deactivate method are the method of
state class which will be called inside stateful widge under state class. it's important
to know that initstate called only once whenever the state method gets build within
stateful Widget. initState needed when we want something to be called once without
build method but if we put that task in another method and put that method inside
build method then build method will recall that method again and again which
slows our app performance. initstate will be called before calling the build method
and when build method destroyed then the deactivate method will be called like if
we go back or forth from that page on which we are currently on.
2. Geolocator() method: Geolocator method comes from the geolocation package
which can be added to packages and can be used to get the location. for further
information use documentation of geolocation on pub.dev.
3. jsonDecode, jsonEncode: these method are use to convert json format into dart
maps and vice versa but first we have to import dart.convert library which
holdings these methods. Json format data in map format but represent like a string
in one line and because http only accept string data to be send that's why it sends
data into a plan text format and when it reaches to it's end then it converts to the
map format which require more space. Now the reason of not using XML instead of
json is because json take less time to travel.
4. Flutter spinkit: A collection of loading indicators animated with flutter.
5. widget instance of stateful class and accessing it 's instance in state class:
6. class LocationScreen extends StatefulWidget {
7. LocationScreen({this.locationWeather});
8. final locationWeather;
9. @override
10. _LocationScreenState createState() => _LocationScreenState();
11. }
12. class _LocationScreenState extends State<LocationScreen> {
13. @override
14. void initState() {
15. super.initState();
16. print(widget.locationWeather);
17. }
now at second last widget is the instance of stateful widget and we can access properties
of locationScreen class through it. and when we go on to the locationScreen init method
will be called and print the weather data to the console.