Would you like to inspect the original subtitles? These are the user uploaded subtitles that are being translated:
0
1
00:00:00,570 --> 00:00:05,980
Now in the last lesson, we vastly simplified and refactored our code.
1
2
00:00:06,240 --> 00:00:10,020
And now it looks a lot simpler and a lot easier to read.
2
3
00:00:10,560 --> 00:00:16,200
But there's just one thing. We know that we're currently using a reusableCard to be able to create a
3
4
00:00:16,200 --> 00:00:23,380
card that has a particular margin or a particular look or a particular rounded border.
4
5
00:00:23,400 --> 00:00:31,950
But we're also adding it as a child to a gesture detector to be able to detect when the user taps on
5
6
00:00:32,010 --> 00:00:36,350
that card, and when that happens we set the selectedGender.
6
7
00:00:36,360 --> 00:00:44,040
Now it's really likely that for other reusable cards, we might also want this functionality, being able
7
8
00:00:44,040 --> 00:00:45,530
to detect touch.
8
9
00:00:45,690 --> 00:00:51,840
And even if we don't need to, there's still two areas where we are repeating the same code right?
9
10
00:00:51,930 --> 00:00:54,620
Adding a gesture detector to the reusableCard.
10
11
00:00:55,050 --> 00:01:01,900
So why don't we just bite the bullet and upgrade our reusableCard to also be able to detect touch?
11
12
00:01:02,070 --> 00:01:05,840
And that's what we're going to do in this lesson. And in the process,
12
13
00:01:05,880 --> 00:01:11,070
I'm going to show you something really cool that you can do with Dart which is passing around functions
13
14
00:01:11,310 --> 00:01:14,130
as if they were just any other object.
14
15
00:01:14,130 --> 00:01:19,440
And I've just noticed that I've actually got a typo in the name of my file.
15
16
00:01:19,650 --> 00:01:25,380
Over here you can see that I've written imput instead of input, but this is really easy to fix because
16
17
00:01:25,380 --> 00:01:27,700
it's not affecting any of our code.
17
18
00:01:27,700 --> 00:01:34,380
So if you ever get a typo or a spelling mistake in your file name, simply just right click on it and
18
19
00:01:34,440 --> 00:01:43,420
click on refactor, rename and it will change all the places where this is used. So let's change that input
19
20
00:01:43,500 --> 00:01:44,710
it will search for references,
20
21
00:01:44,730 --> 00:01:52,080
search for comments and strings and it'll refactor everything to the right spelling. In Dart,functions
21
22
00:01:52,160 --> 00:01:53,980
are first class citizens.
22
23
00:01:54,000 --> 00:01:59,250
This means that they have a type and they can be passed around just like any other type
23
24
00:01:59,250 --> 00:02:06,300
for example a string or an int. And they can also be set as the value of a variable or a constant.
24
25
00:02:06,330 --> 00:02:09,360
So let's take a look at this now.
25
26
00:02:09,480 --> 00:02:13,050
So here in my DartPad, I've got two functions.
26
27
00:02:13,050 --> 00:02:18,060
One is a function called add which simply as the two numbers that it's given.
27
28
00:02:18,180 --> 00:02:19,290
And the second one is called
28
29
00:02:19,290 --> 00:02:23,030
multiply and it multiplies the two numbers that it's given.
29
30
00:02:23,040 --> 00:02:30,990
Now if I wanted to perform a calculation, I could say add and then provide my numbers 3 and 5
30
31
00:02:31,050 --> 00:02:35,210
for example, and then I would end up with a result.
31
32
00:02:35,340 --> 00:02:42,960
So let's call it a int result equals the result of the add and then we'll print the result to the console.
32
33
00:02:43,650 --> 00:02:47,050
And you can see that I will be able to run it as it is.
33
34
00:02:47,400 --> 00:02:54,030
But what if I wanted to build a calculator where the user is able to tap on the plus button or the minus
34
35
00:02:54,030 --> 00:02:57,330
button and perform the calculation that they need?
35
36
00:02:57,330 --> 00:03:01,730
Well what if instead of having to call a different function each time instead,
36
37
00:03:01,920 --> 00:03:11,550
what if I create a new function that returns an int and it's called calculator and it not only takes
37
38
00:03:11,640 --> 00:03:19,390
two numbers int n1 and int n2, but it can also take a function as an argument?
38
39
00:03:19,440 --> 00:03:22,380
So we would be able to add it as a type.
39
40
00:03:22,410 --> 00:03:27,300
So for a string it would be string for an int it would be an int. But for function we would just write the
40
41
00:03:27,300 --> 00:03:30,470
name Function with a capital F. And we could give it a name
41
42
00:03:30,480 --> 00:03:33,140
let's call it calculation.
42
43
00:03:33,140 --> 00:03:41,280
And then inside the body of the function, I will perform the calculation on those two numbers n1 and
43
44
00:03:41,370 --> 00:03:49,740
n2. And then I would return the result of this calculation as the output of my calculator.
44
45
00:03:49,740 --> 00:03:56,820
Now what I'm able to do is instead of having to call add then multiply then whatever, then in this case
45
46
00:03:56,910 --> 00:04:04,770
I could simply write the result is going to be calculator performing a function on two numbers, let's
46
47
00:04:04,770 --> 00:04:10,380
call it 5 and 8, and then the third input here is a function.
47
48
00:04:10,380 --> 00:04:14,300
It's expecting an actual function as an input.
48
49
00:04:14,310 --> 00:04:16,620
So I'm simply going to add the name.
49
50
00:04:16,680 --> 00:04:22,950
So for example, add. Well in this case, it's clear that I want my calculator to perform some sort of function
50
51
00:04:23,040 --> 00:04:26,730
on 5 and 8 and then add them together.
51
52
00:04:26,760 --> 00:04:31,690
So now if I hit run you can see that it's going to try and add 5 and 8 together.
52
53
00:04:31,800 --> 00:04:40,170
But if I simply switch out the parameter here into multiply, as long as I spell it right, then it will
53
54
00:04:40,260 --> 00:04:42,900
multiply 5 and 8 together.
54
55
00:04:42,900 --> 00:04:49,440
So functions are being passed around just as any other types, so if it was an int or if it was a string.
55
56
00:04:49,710 --> 00:04:56,630
And this gives us a lot of flexibility and it's really powerful as we'll come to see. Now
56
57
00:04:56,640 --> 00:05:04,260
the other thing that we can do with functions is we can even assign a function as the value of a variable.
57
58
00:05:04,590 --> 00:05:11,490
So for example instead of saying int calculator, I could simply create a new variable that is of type
58
59
00:05:11,490 --> 00:05:19,290
Function and I could call it calculator and I will set it to equal my function here. And at the very
59
60
00:05:19,290 --> 00:05:22,200
end, I just have to cap it off with a semicolon.
60
61
00:05:22,230 --> 00:05:25,200
So now it works exactly the same way as before.
61
62
00:05:25,230 --> 00:05:33,780
If I click run and I change it to add or multiply, doesn't really matter, it still works as is. My function
62
63
00:05:34,260 --> 00:05:40,750
is now stored inside a variable called calculator and I could even make this a final variable if I wished
63
64
00:05:40,760 --> 00:05:41,040
to.
64
65
00:05:41,220 --> 00:05:47,520
Which means that I'm no longer able to change the assignment of my calculator so I can't say calculator
65
66
00:05:47,550 --> 00:05:53,370
now equals a different function for example. It'll give me an error telling me that calculator is a final
66
67
00:05:53,370 --> 00:05:57,750
variable and can only be set once.
67
68
00:05:57,750 --> 00:06:03,870
Now notice how at the moment, I'm creating functions completely outside of any classes and even outside
68
69
00:06:03,930 --> 00:06:05,280
of the main function.
69
70
00:06:05,410 --> 00:06:07,750
And this is perfectly legal in Dart.
70
71
00:06:07,830 --> 00:06:14,150
You can have top level functions just like this and they are not associated with any class or object.
71
72
00:06:14,670 --> 00:06:16,980
But let's see how it works inside a class.
72
73
00:06:16,980 --> 00:06:25,560
So I'm going to delete all the code so far and I'm going to create a new class called Car. And car is
73
74
00:06:25,560 --> 00:06:32,580
going to have a property that is a function and it's going to be called drive.
74
75
00:06:32,580 --> 00:06:37,740
Now this property will be initialized when car gets constructed.
75
76
00:06:37,800 --> 00:06:46,890
So I'm going to create my car constructor and I'm going to write this.drive to say that when I construct
76
77
00:06:46,950 --> 00:06:53,520
my car, I have to provide a drive method to associate it with my car object.
77
78
00:06:54,930 --> 00:07:02,760
Let's say that we have two modes of driving right? Let's create one which is called slowDrive, and in
78
79
00:07:02,760 --> 00:07:06,630
this case it's simply going to print 'driving slowly'.
79
80
00:07:09,240 --> 00:07:14,220
And then let's say we have another one which is called fast drive
80
81
00:07:14,880 --> 00:07:22,500
and in this case it will print 'driving super fast.'
81
82
00:07:22,790 --> 00:07:23,110
All right.
82
83
00:07:23,140 --> 00:07:29,200
So now I have two functions which are top level functions. They are not associated with any class. But when
83
84
00:07:29,200 --> 00:07:38,650
I initialize my car in my main function, for example I could say myCar is equal to a new car which
84
85
00:07:38,650 --> 00:07:40,910
is constructed from the Car class.
85
86
00:07:41,020 --> 00:07:46,130
And I now have to provide a value for the drive property.
86
87
00:07:46,210 --> 00:07:50,120
So the drive property is going to be set equal a function
87
88
00:07:50,140 --> 00:07:50,570
right?
88
89
00:07:50,590 --> 00:07:51,960
So it's expecting a function.
89
90
00:07:51,970 --> 00:07:58,920
I can't just put in a number, say 2 or I can't put in a string because it needs to be of the type function.
90
91
00:07:58,930 --> 00:08:03,820
So let's give it a function because we have to. We can either say slowDrive or fastDrive.
91
92
00:08:03,820 --> 00:08:07,490
Well let's say that my car starts out being a slowDrive car.
92
93
00:08:07,690 --> 00:08:12,670
And notice how I'm not actually adding any parentheses after the function.
93
94
00:08:12,670 --> 00:08:16,330
I'm simply passing over the name of that function.
94
95
00:08:16,360 --> 00:08:23,590
So now at this stage myCar.drive is associated with the slowDrive function.
95
96
00:08:23,590 --> 00:08:28,320
So I could show you this by simply running print myCar.drive.
96
97
00:08:28,510 --> 00:08:34,390
And notice again I'm not putting a set of parentheses after drive because that is the thing that will
97
98
00:08:34,390 --> 00:08:35,850
activate the function.
98
99
00:08:35,860 --> 00:08:39,910
So right now if I print, you'll notice it'll print Closure 'slowDive'.
99
100
00:08:39,910 --> 00:08:43,300
So that's pointing to this particular function.
100
101
00:08:43,390 --> 00:08:49,770
It's saying that in myCar the drive property is equal to slowDrive.
101
102
00:08:49,900 --> 00:08:55,450
But if I actually wanted to call my drive method, I would say myCar.drive.
102
103
00:08:55,600 --> 00:08:59,500
And I would add the parentheses and any inputs if necessary.
103
104
00:08:59,500 --> 00:09:05,520
And it's this line that actually triggers the drive method that is associated with my car.
104
105
00:09:05,950 --> 00:09:09,270
And we're getting driving slowly printed to the console.
105
106
00:09:09,340 --> 00:09:12,250
Now let's say that I wanted to upgrade my car right?
106
107
00:09:12,280 --> 00:09:13,470
I will say myCar
107
108
00:09:13,490 --> 00:09:19,270
.drive, the drive property is now going to be equal to fastDrive.
108
109
00:09:19,270 --> 00:09:21,880
And again no parentheses after the method.
109
110
00:09:21,880 --> 00:09:27,340
But I'm simply changing the value of that drive property on myCar.
110
111
00:09:27,340 --> 00:09:29,190
So now I've taken my car to the garage.
111
112
00:09:29,200 --> 00:09:34,450
It's being souped up. Now it's going to turbo and it's supercharged and it's blazing.
112
113
00:09:34,450 --> 00:09:40,750
So now when I write myCar.drive and we print out the result.
113
114
00:09:40,810 --> 00:09:43,180
So I'm going to comment out that line.
114
115
00:09:43,180 --> 00:09:52,390
And now you can see that myCar's been upgraded and now it's driving super fast. When I'm passing functions
115
116
00:09:52,390 --> 00:09:55,280
around, I'm just using its name.
116
117
00:09:55,390 --> 00:09:57,200
I'm not adding the parentheses.
117
118
00:09:57,250 --> 00:10:03,610
And when I want to call the method and actually trigger the functionality that's when I add the parentheses
118
119
00:10:03,760 --> 00:10:12,570
and any inputs if necessary. Now that we've seen how flexible functions can be and how they can be passed
119
120
00:10:12,570 --> 00:10:16,430
around just like any other object or any other type,
120
121
00:10:16,590 --> 00:10:21,570
it's time for your challenge to apply what you've learned to our code.
121
122
00:10:21,570 --> 00:10:29,340
The goal of the challenge is to do the gesturedetector on the first icon card and also the second
122
123
00:10:29,340 --> 00:10:33,390
one and refactor it into the reusableCard
123
124
00:10:33,390 --> 00:10:41,400
.dart file. So that way we can actually pass a function into our reusableCard just as we've passed
124
125
00:10:41,460 --> 00:10:50,130
a color property or a cardChild and our function is also going to be passed as a value for one of these
125
126
00:10:50,340 --> 00:10:51,390
properties.
126
127
00:10:51,420 --> 00:10:56,370
So if you're successful by the end nothing about your app will have changed other than the fact that
127
128
00:10:56,370 --> 00:11:02,220
the gesture detector should now live in the reusableCard and inside this build method.
128
129
00:11:02,700 --> 00:11:08,540
Pause the video and see if you can solve this challenge. All right.
129
130
00:11:08,560 --> 00:11:14,290
So first things first. I'm going to simply delete my gesture detector from this page. So I'm going to
130
131
00:11:14,290 --> 00:11:20,980
hold down OPTION or ALT, hit ENTERand I'm going to remove my widget from both places.
131
132
00:11:21,400 --> 00:11:25,910
So both in the first card and the second card.
132
133
00:11:26,170 --> 00:11:32,560
Now I just have a pure reusableCard and I'm going to pass over the functionality where I set state
133
134
00:11:32,620 --> 00:11:39,630
and change the selectedGender when the user clicks on this card or this card into my reusableCard.
134
135
00:11:39,640 --> 00:11:45,700
So inside here in the build method, instead of just returning a container, I'm actually going to wrap
135
136
00:11:45,700 --> 00:11:48,850
the container inside a gesture detector.
136
137
00:11:50,870 --> 00:11:59,360
And here of course I will now again have access to the onTap. And I'm going to pass over a function
137
138
00:11:59,540 --> 00:12:02,810
into my reusableCard widget.
138
139
00:12:02,840 --> 00:12:09,350
So in exactly the same way that we did with our previous two properties, color and cardChild, I'm going
139
140
00:12:09,350 --> 00:12:14,640
to add another final property which is going to have a function as the type.
140
141
00:12:14,780 --> 00:12:22,520
And I'm going to call it onPress. And this is also going to be initialized when I create a new reusable
141
142
00:12:22,520 --> 00:12:22,850
Card.
142
143
00:12:22,880 --> 00:12:29,060
So I'm going to add the this.onPress over here so that I can pass over whichever function I want
143
144
00:12:29,060 --> 00:12:32,640
to be used inside my reusableCard.
144
145
00:12:32,810 --> 00:12:37,810
And then it's going to be set as the value of the onTap.
145
146
00:12:37,820 --> 00:12:44,360
So this means that when I create a reusableCard, I can specify a function that is going to be the function
146
147
00:12:44,360 --> 00:12:49,880
that will be called when the gesture detector detects a tap on the reusableCard.
147
148
00:12:50,300 --> 00:12:57,620
So now I can go back to my input page and add some properties to my reusableCard. So I can add my on
148
149
00:12:57,620 --> 00:13:00,320
Press which I just defined just now,
149
150
00:13:00,320 --> 00:13:04,010
and it's going to be the same as what we would have done with the gesture detector.
150
151
00:13:04,010 --> 00:13:09,920
We're going to add an anonymous function and inside the anonymous function, we have our set state and
151
152
00:13:09,920 --> 00:13:10,870
inside the set state,
152
153
00:13:10,880 --> 00:13:19,700
we change the selectedGender to gender.male in the first reusableCard and in our second reusable
153
154
00:13:19,700 --> 00:13:20,360
card,
154
155
00:13:20,480 --> 00:13:31,200
we have our onPress and in this case the set state is going to change the selectedGender to female. Now
155
156
00:13:31,260 --> 00:13:40,150
when I hit save on my code, nothing about my app will change. You can see that it still works exactly
156
157
00:13:40,150 --> 00:13:47,640
the same way as it did before, but now we've simply refactored the ability for our reusableCard,
157
158
00:13:47,650 --> 00:13:54,370
this custom widget that we've built based on gesture detector, based on containers, based on box decorations
158
159
00:13:54,370 --> 00:14:02,240
etc. and it's now also able to take a onPress. So it's able to respond to taps.
159
160
00:14:02,290 --> 00:14:08,440
So we've essentially upgraded our reusableCard to also be able to detect touch simply by passing
160
161
00:14:08,440 --> 00:14:18,470
over a function as the value of the onPress property. And the result of this is cleaner code with less
161
162
00:14:18,470 --> 00:14:26,180
things being embedded and all the functionality and the design is now together in one widget.
162
163
00:14:26,180 --> 00:14:30,690
It's always good practice to refactor your code as you go along.
163
164
00:14:30,890 --> 00:14:36,720
This way you don't end up with spaghetti code at the end and lose all motivation to tidy it up.
164
165
00:14:36,740 --> 00:14:42,590
You know that when your room gets to a certain state where it's just no longer possible to recover it
165
166
00:14:42,650 --> 00:14:43,670
and then you give up.
166
167
00:14:43,790 --> 00:14:45,160
That's not what we want with our code.
167
168
00:14:45,170 --> 00:14:48,140
We want it to be neat and tidy and performance.
168
169
00:14:48,140 --> 00:14:54,050
Now in the next lesson, we're going to continue working on the other cards that we have in our user interface.
169
170
00:14:54,500 --> 00:15:01,870
And we're going to implement a Flutter slider to be able to select the user's height on a scale.
170
171
00:15:01,880 --> 00:15:04,580
So for all of that and more, I'll see on the next lesson.
19681
Can't find what you're looking for?
Get subtitles in any language from opensubtitles.com, and translate them here.