0 1 00:00:00,180 --> 00:00:00,480 All right. 1 2 00:00:00,510 --> 00:00:06,090 So now that we've seen the awesomeness of dark mode as well as vector image assets, it's time to move 2 3 00:00:06,090 --> 00:00:11,640 on to the next thing which is learning how to use the UITextField. 3 4 00:00:11,640 --> 00:00:16,010 Let's take a closer look at our text field in the Interface Builder. 4 5 00:00:16,020 --> 00:00:24,030 Notice how we've got a text field right here which you can find from the object library. And it's right 5 6 00:00:24,030 --> 00:00:24,990 here. 6 7 00:00:24,990 --> 00:00:33,390 The text field is going to allow the user to use the keyboard on the iPhone and type in an input. 7 8 00:00:33,390 --> 00:00:40,590 By default Apple's UITextField already knows how to handle light and dark modes, so that the color 8 9 00:00:40,590 --> 00:00:44,370 of the tags depending on which mode we're in will be different. 9 10 00:00:44,370 --> 00:00:51,840 So it will be white in dark mode and it will black in light mode, and the background color also adjusts depending 10 11 00:00:51,840 --> 00:00:54,300 on the interface style. 11 12 00:00:54,560 --> 00:01:01,990 Now, we can also set the type of keyboard that we want by changing these text input traits. 12 13 00:01:02,030 --> 00:01:10,400 So for example, we could say that the capitalization for our inputs should be for each word because our 13 14 00:01:10,400 --> 00:01:13,540 users are going to be typing in the names of cities. 14 15 00:01:13,550 --> 00:01:20,120 So for example, this means that if they start typing the word "London," then it will automatically capitalize 15 16 00:01:20,120 --> 00:01:28,800 the "L" here. And we've also got other things, such as the type of keyboard, so you can change the keyboard 16 17 00:01:28,800 --> 00:01:37,140 that pops up to a number pad or one that is for e-mail addresses or Twitter. And we can also change what's 17 18 00:01:37,140 --> 00:01:38,240 in the return key. 18 19 00:01:38,430 --> 00:01:42,800 So the Default just says return, and you should be familiar with that 19 20 00:01:42,810 --> 00:01:48,900 if you use the iPhone keyboard often. But I'm going to change it to Go because it seems to make more 20 21 00:01:48,900 --> 00:01:52,260 sense when we are searching for the weather in a city. 21 22 00:01:52,260 --> 00:01:57,970 And finally, I want to show you that you can also change the text to be Secure Text Entry. 22 23 00:01:58,020 --> 00:02:03,810 So what this means is that when you have some text that is for a password field, you don't actually see 23 24 00:02:03,810 --> 00:02:08,790 the actual text, so that somebody who's looking over your user's shoulders, won't be able to know what 24 25 00:02:08,790 --> 00:02:10,850 their password is. 25 26 00:02:10,890 --> 00:02:11,220 All right. 26 27 00:02:11,250 --> 00:02:15,990 So now that we've seen this text field, let's go ahead and set it up. 27 28 00:02:15,990 --> 00:02:21,550 So I've left all of this for you to do, so you can see how to set up a UItTextField from scratch. 28 29 00:02:21,600 --> 00:02:28,050 Now, let's go ahead and control-click to create a new IBOutlet which I'm going to call the searchTextField, 29 30 00:02:28,050 --> 00:02:39,720 and then I'm going to add a IBAction from this search button to say searchPressed, and then change 30 31 00:02:39,720 --> 00:02:42,290 the data type to a UIButton. 31 32 00:02:42,360 --> 00:02:49,410 And now I can tap into this IPBAction and see what the user's typed in the search field. 32 33 00:02:49,410 --> 00:02:55,290 So the idea here is that the user would tap on this field, type in the name of the city, and then press the 33 34 00:02:55,350 --> 00:02:59,090 search button at which point, we'll be able to see what they typed. 34 35 00:02:59,100 --> 00:03:06,000 So as you might guess, the text field has some pretty common properties like the one that we saw earlier 35 36 00:03:06,360 --> 00:03:09,990 when we were setting it in the Main.storyboard. 36 37 00:03:09,990 --> 00:03:16,330 So if you select the text field, you can see it's got a text property like a label, but this corresponds 37 38 00:03:16,330 --> 00:03:19,500 to the text that the user has typed inside here. 38 39 00:03:20,040 --> 00:03:27,000 So we can get a hold of it by tapping into the searchTextField.text property which, again, corresponds 39 40 00:03:27,000 --> 00:03:29,970 to the text displayed by the text field. 40 41 00:03:29,970 --> 00:03:35,400 Now, that's different from the text that you see here in sort of a light color. 41 42 00:03:35,400 --> 00:03:37,660 That is the placeholder text. 42 43 00:03:37,760 --> 00:03:40,920 And this is kind of meant to be like the reminder for the user. 43 44 00:03:40,980 --> 00:03:46,320 This is what you should type into this text field like it might say "Password" if it was in the password 44 45 00:03:46,320 --> 00:03:53,480 field, or it might say "Enter a city name" if it's in this particular field. But it's kind of up to you. 45 46 00:03:53,490 --> 00:03:57,360 But I think search seems to make sense for me. 46 47 00:03:57,360 --> 00:04:01,230 This is where you're going to search for a city name. 47 48 00:04:01,410 --> 00:04:07,870 And now we can go ahead and try to print what's inside our searchField.text. 48 49 00:04:08,010 --> 00:04:16,430 So because the text property is a optional string because it doesn't have to be set, 49 50 00:04:16,430 --> 00:04:18,850 it could also just be an empty string, 50 51 00:04:18,980 --> 00:04:23,810 and, in fact, it tells you that the string is empty by default. 51 52 00:04:23,810 --> 00:04:29,960 So we can go ahead and unwrap that if we want to print it without that little yellow warning because 52 53 00:04:29,960 --> 00:04:31,400 we know that it's an optional, 53 54 00:04:31,400 --> 00:04:35,450 and we know that we're going to type something into it when we print it to see its value. 54 55 00:04:35,900 --> 00:04:43,410 So let's go ahead and run the app and see what we get. So when our app runs and you click in the search 55 56 00:04:43,410 --> 00:04:50,670 field, it should bring up the soft keyboard, so the keyboard that's attached to the iPhone. If it doesn't 56 57 00:04:50,670 --> 00:04:58,470 bring it up, then you can go into the Hardware menu for the simulator, and go to Keyboard and Toggle Software 57 58 00:04:58,500 --> 00:05:02,070 Keyboard, or just use the shortcut of command K. 58 59 00:05:02,310 --> 00:05:06,500 And that should hide or bring back the soft keyboard. 59 60 00:05:06,510 --> 00:05:12,660 `Now when I start typing in here, you'll notice that we've currently got our Secure Text Entry selected, 60 61 00:05:13,080 --> 00:05:19,960 and we've also managed to change the return key from the default which says return to go. 61 62 00:05:20,010 --> 00:05:27,390 So I'm gonna go ahead and uncheck that Secure Text Entry. So I can see my words being capitalized even 62 63 00:05:27,390 --> 00:05:35,150 without me hitting shift. Now that we've seen all keyboard in action, let's go ahead and click on the 63 64 00:05:35,150 --> 00:05:42,050 search button, and you should be able to see the words that you've typed in their printed down here. 64 65 00:05:43,210 --> 00:05:49,090 That is because we're tapping into these searchTextField IBOutlet and then getting its text property 65 66 00:05:49,360 --> 00:05:49,990 printed. 66 67 00:05:50,950 --> 00:06:00,160 But you'll notice that when I type a word in here, let's say, "London," and click on the go button, 67 68 00:06:00,160 --> 00:06:06,790 nothing actually happens, even though you would expect that it would have the same behavior as our search 68 69 00:06:06,790 --> 00:06:07,510 button. 69 70 00:06:07,510 --> 00:06:10,570 So how do we tap into that go button? 70 71 00:06:10,570 --> 00:06:14,130 Well, it's a little bit different from what you might expect. 71 72 00:06:14,140 --> 00:06:22,240 We can't simply just create an IBOutlet to the keyboard and get a hold of when the keyboard go button 72 73 00:06:22,240 --> 00:06:23,370 gets pressed. 73 74 00:06:23,470 --> 00:06:32,050 Instead, we have to use something called a UITextFieldDelegate. So the first thing we need to do is 74 75 00:06:32,050 --> 00:06:41,410 we need to add a comma after the UIViewController and type UITextFieldDelegate. 75 76 00:06:41,410 --> 00:06:49,240 And this will allow our class, our weather view controller, to manage the editing and validation of text 76 77 00:06:49,330 --> 00:06:50,890 in a text field. 77 78 00:06:50,950 --> 00:06:56,800 So let's hit enter to add that. The next step is inside our viewDidLoad. 78 79 00:06:56,800 --> 00:07:04,030 I'm going to delete the comment there, but I'm going to tap into that searchTextField and tap into 79 80 00:07:04,030 --> 00:07:12,430 the delegate property to set it as this current class which is, of course, accessed using that "self" 80 81 00:07:12,430 --> 00:07:20,050 keyword. Here what this line of code is saying is the text field should report back to our view controller. 81 82 00:07:20,650 --> 00:07:27,400 For example, our text field will handle the task of our user entering text. When the user interacts with 82 83 00:07:27,400 --> 00:07:28,280 our text field, 83 84 00:07:28,280 --> 00:07:35,030 say, your user type something, then or text field will notify our view controller on what's happening. 84 85 00:07:35,380 --> 00:07:37,640 The text field will say something like, 85 86 00:07:37,690 --> 00:07:38,720 "Hey, view controller, 86 87 00:07:38,920 --> 00:07:45,250 the user just started typing," or the text field will say something like, "Oye, view controller, 87 88 00:07:45,250 --> 00:07:47,440 the user just stopped typing," 88 89 00:07:47,440 --> 00:07:53,500 or it might even say something like, "Yo, view controller, the user just try to tap elsewhere, should I 89 90 00:07:53,500 --> 00:07:55,560 let them deselect me?" 90 91 00:07:55,600 --> 00:08:01,030 The idea here is that the text field can communicate what's going on. And the way we ensure that the view 91 92 00:08:01,030 --> 00:08:07,060 controllers notified by the text field is by setting the view controller as the delegate. 92 93 00:08:07,060 --> 00:08:10,270 Remember that "self" refers to the current view controller. 93 94 00:08:11,500 --> 00:08:20,650 So what this allows us to do these two steps is we can now create a method called 94 95 00:08:20,800 --> 00:08:26,560 textFieldShouldReturn. And this will ask the delegate which is this current class 95 96 00:08:26,710 --> 00:08:32,150 if the text field should process the pressing of the return button. 96 97 00:08:32,410 --> 00:08:38,840 In other words, the text field will say, "Hey, view controller, the user pressed the return key in the keyboard." 97 98 00:08:38,950 --> 00:08:40,500 What should we do? 98 99 00:08:40,570 --> 00:08:46,690 This is going to be the exact time point when the return button gets pressed and I get to write some 99 100 00:08:46,690 --> 00:08:54,130 code to be triggered at this point. But once I'm done writing my code, I also have to return a true or 100 101 00:08:54,130 --> 00:09:00,310 false that tells the text field whether if it should actually process that return. 101 102 00:09:00,310 --> 00:09:06,520 In my case, what I'm gonna do is I'm just going to use this as if I have an IBAction to that return 102 103 00:09:06,520 --> 00:09:15,610 button. And I'm going to print my searchTextField.text and I'm gonna force unwrap it. And finally, 103 104 00:09:15,670 --> 00:09:23,290 we have to return true because this is a function that expects a boolean as an output, so that our text 104 105 00:09:23,290 --> 00:09:26,480 field will be allowed to actually return. 105 106 00:09:26,500 --> 00:09:37,380 So now if we hit run and we type a word into our text field and then go ahead and click on the return 106 107 00:09:37,380 --> 00:09:37,870 button, 107 108 00:09:37,890 --> 00:09:44,640 so this has been renamed go, but this is always known as the return button of the keyboard, then it will 108 109 00:09:44,640 --> 00:09:51,960 trigger this function textFieldShouldReturn and we get the text inside our search field printed down 109 110 00:09:51,960 --> 00:10:01,580 here, and we allow this return process to go through with our return true. So now we can get hold of what 110 111 00:10:01,580 --> 00:10:07,460 the users typed into the text field from two places, either if they've typed in something and then press 111 112 00:10:07,460 --> 00:10:13,040 the search button, or if they've typed something and then press the go button. 112 113 00:10:13,040 --> 00:10:19,370 I know that a lot of people, at least me included, when I'm typing inside the keyboard, it's much quicker 113 114 00:10:19,370 --> 00:10:22,040 for my thumb to reach the go button, 114 115 00:10:22,040 --> 00:10:27,380 and I expect it to basically hit enter, kind of like the return key on a keyboard. 115 116 00:10:27,380 --> 00:10:33,680 So both of these buttons now trigger the same thing which is for me to be able to get hold of what's 116 117 00:10:33,770 --> 00:10:40,520 inside the searchTextField. But there is just one problem at the moment, I can't seem to get rid of 117 118 00:10:40,520 --> 00:10:47,690 this keyboard no matter where I click, or if I click on the search or the go, it doesn't dismiss itself 118 119 00:10:47,720 --> 00:10:48,700 like it should do. 119 120 00:10:48,710 --> 00:10:53,000 It should kind of disappear because I'm saying I'm done with it now. 120 121 00:10:53,210 --> 00:10:56,680 So how can we fix this? 121 122 00:10:56,700 --> 00:11:03,150 Well, we can tell our IBAction searchPressed that in addition to printing the searchFieldText, it 122 123 00:11:03,150 --> 00:11:08,270 should also make our search field and editing. 123 124 00:11:08,400 --> 00:11:15,720 So, if we tap into this method code endEditing and set it to true, then it will tell the search field 124 125 00:11:15,750 --> 00:11:18,870 that we're done with editing and you can dismiss the keyboard. 125 126 00:11:19,380 --> 00:11:25,800 So let's put that in both places, the text field should return as well as the searchPressed. 126 127 00:11:26,370 --> 00:11:35,110 So now when we run our app and I go ahead and type something into my text field and I press the search 127 128 00:11:35,110 --> 00:11:38,550 button, then it dismisses my keyboard. 128 129 00:11:38,560 --> 00:11:43,480 Similarly, if I press the go button, it also dismisses my keyboard. 129 130 00:11:43,480 --> 00:11:52,660 So perfect. Now, what if we wanted to be able to clear what's in the text field to set it back to its 130 131 00:11:52,660 --> 00:11:53,760 original state, 131 132 00:11:53,950 --> 00:12:00,790 Once we click on the go button or the search button because at the moment, it's kind of leaving it in 132 133 00:12:00,790 --> 00:12:06,550 there, even though we said that we're done with editing of the text field and we can dismiss the keyboard. 133 134 00:12:06,550 --> 00:12:09,550 It's kind of weird to leave the text in there. 134 135 00:12:09,550 --> 00:12:16,380 So how can we tap into this moment when the text field has ended editing? 135 136 00:12:16,380 --> 00:12:19,500 Well, there's a delegate method for that. 136 137 00:12:19,600 --> 00:12:26,170 Remember, the delegate is the one who is notified. By being the delegate of the text field, our view controller 137 138 00:12:26,200 --> 00:12:33,360 can be notified when the text field ends editing. Similar to how we got hold of textFieldShouldReturn, 138 139 00:12:33,460 --> 00:12:37,900 we can get hold of a method called textFieldDidEndEditing. 139 140 00:12:37,900 --> 00:12:44,890 This is the equivalent of our text field saying, "Hey, view controller, the user stopped editing." And inside 140 141 00:12:44,950 --> 00:12:51,700 this bracket, the code will be triggered as soon as any of the text fields on the screen are done with 141 142 00:12:51,790 --> 00:12:52,960 editing. 142 143 00:12:52,960 --> 00:13:01,250 So inside here, we can set the searchTextFields.text property to equal a empty string. 143 144 00:13:01,600 --> 00:13:10,250 And when we run this code, you can see that as soon as I'm done with my typing and I press go, it clears 144 145 00:13:10,310 --> 00:13:17,990 my text field so that I can type a new search term the next time, and it works both from my search button 145 146 00:13:18,410 --> 00:13:20,300 as well as from my go button. 146 147 00:13:22,040 --> 00:13:28,140 A nice thing about setting the textField.text property to an empty string using 147 148 00:13:28,170 --> 00:13:31,740 textFieldDidEndEditing is that we avoid a bit of repetition. 148 149 00:13:31,740 --> 00:13:38,070 Otherwise, we would have to do this twice. First, on line 26 after the search button is pressed, and then 149 150 00:13:38,130 --> 00:13:42,730 ,again, on line 31 after the return key is pressed. 150 151 00:13:42,820 --> 00:13:50,490 Now, there's one final delegate method that's quite useful and it's called the 151 152 00:13:50,510 --> 00:13:51,660 textFieldShouldEndEditing. 152 153 00:13:51,660 --> 00:13:56,130 So if we type in the textFieldShouldEndEditing, 153 154 00:13:56,130 --> 00:14:01,710 you can see that, again, it expects a boolean as the output. 154 155 00:14:01,710 --> 00:14:07,740 Notice how all the methods that have the word "should" in the name are asking for permission. 155 156 00:14:07,740 --> 00:14:13,200 This is the text field saying, "Excuse me, view controller, the user just tapped elsewhere. 156 157 00:14:13,200 --> 00:14:14,220 What should I do sir?" 157 158 00:14:14,220 --> 00:14:16,600 Should I allow them to stop editing? 158 159 00:14:17,110 --> 00:14:22,920 Here our view controller gets to decide what happens when the user tries to deselect the text field. 159 160 00:14:23,070 --> 00:14:28,340 But wait, why might you want to prevent your user to stop editing a text field? 160 161 00:14:28,350 --> 00:14:30,660 Why trap them in editing mode? 161 162 00:14:30,690 --> 00:14:37,410 Well, the textFieldShouldEndEditing method is actually really useful for doing some validation on 162 163 00:14:37,410 --> 00:14:38,640 what the user typed. 163 164 00:14:39,770 --> 00:14:49,400 So for example, we might want to check to see if the textField.text property is not equal to an 164 165 00:14:49,400 --> 00:14:53,820 empty string because the user should really type something in there. 165 166 00:14:53,900 --> 00:14:59,780 If we're gonna use that text to check for the weather, then we're kind of assuming that they've type 166 167 00:14:59,780 --> 00:15:03,160 something, rather than it being an empty string, right? 167 168 00:15:03,740 --> 00:15:09,500 So in this case, well, then we're going to allow our text field to return. So we're gonna say, 168 169 00:15:09,500 --> 00:15:17,960 "true," it should end editing. But if it's actually equal to an empty string, then we're going to remind 169 170 00:15:18,020 --> 00:15:25,160 or alert the user that they have to write something. And to do that, one of the easiest ways is tapping 170 171 00:15:25,160 --> 00:15:27,710 into the placeholder property. 171 172 00:15:27,710 --> 00:15:35,750 So remember that inside our Main.storyboard, we set our placeholder property to say, "Search," which 172 173 00:15:35,750 --> 00:15:39,200 is what shows up in sort of a light gray color. 173 174 00:15:39,230 --> 00:15:44,720 But in this case, we're going to change the placeholder to something to alert them that they should 174 175 00:15:44,990 --> 00:15:47,210 type something here. 175 176 00:15:47,870 --> 00:15:50,840 And then after that, we're going to return false. 176 177 00:15:50,840 --> 00:15:56,510 We're not going to let the text field and editing yet. We're going to keep the keyboard where it is and 177 178 00:15:56,510 --> 00:16:03,410 we're not going to trigger this method. And you can see that when I click in the text field and I try 178 179 00:16:03,410 --> 00:16:10,580 to click return or click the search button and I haven't typed anything, then it's reminding me to type 179 180 00:16:10,580 --> 00:16:18,220 something in here before it will dismiss the keyboard, end editing, and reset the text field. 180 181 00:16:18,330 --> 00:16:25,740 Now, one thing that I want you to notice here is that notice how in these methods, I've been using that 181 182 00:16:25,800 --> 00:16:33,640 IBOutlet we have created, the search text field which, of course, is a reference to that text field we 182 183 00:16:33,640 --> 00:16:43,240 have in our screen. But down here in this new method, I've actually just referred to a textField. 183 184 00:16:43,240 --> 00:16:46,000 So where does that come from? 184 185 00:16:46,000 --> 00:16:53,350 Well, remember that we are not the ones triggering or calling any of these functions, right? 185 186 00:16:53,470 --> 00:17:00,160 Nowhere in our code do we call text field should return or textFieldShouldEndEditing because they are 186 187 00:17:00,160 --> 00:17:07,810 triggered by the text field. So the text field class is the one that's responsible for calling these 187 188 00:17:07,810 --> 00:17:15,680 methods. And when it calls textFieldShouldEndEditing, when it detects the user dismissing the keyboard, 188 189 00:17:15,730 --> 00:17:23,170 well, then in that moment, it's gonna pass in a reference to the textField that triggered this method. 189 190 00:17:23,620 --> 00:17:30,610 So you could, for example, have a multiple text fields, similar to how in our IBAction, we can get hold of 190 191 00:17:30,610 --> 00:17:39,640 the sender which was the UIButton that actually triggered this IBAction by detecting a touch event. 191 192 00:17:39,640 --> 00:17:48,440 We can have multiple text fields or triggering the same methods. So if we had multiple buttons linked 192 193 00:17:48,500 --> 00:17:53,410 to the same IBAction, then any of those buttons could be the sender. 193 194 00:17:53,420 --> 00:17:56,180 It just depends on who detected the event. 194 195 00:17:56,450 --> 00:18:03,290 And if we have a bountiful text fields, all with their delegates set as this current class, then any of 195 196 00:18:03,290 --> 00:18:09,620 those text fields could be the trigger for these delegate methods, but they will pass their identity 196 197 00:18:09,770 --> 00:18:17,120 in through this text field parameter. So if we don't care about which text field was triggered, then we 197 198 00:18:17,120 --> 00:18:25,670 can simply just use this parameter and apply our validation to any text field in our current view controller 198 199 00:18:25,670 --> 00:18:28,190 using this code. 199 200 00:18:28,420 --> 00:18:34,900 So now that we've implemented our text field, the final thing that we want is no matter if they pressed 200 201 00:18:34,900 --> 00:18:41,140 on the search button or if they pressed on the return or go button, we should be able to get hold of 201 202 00:18:41,140 --> 00:18:48,220 what it is that they wrote which is the textField. text property. And I want to be able to use that 202 203 00:18:48,250 --> 00:18:53,770 which, hopefully, contains the city name to check for the weather in that city. 203 204 00:18:54,040 --> 00:18:59,990 The perfect place to do that is in our textFieldDidEndEditing method. 204 205 00:19:00,280 --> 00:19:08,710 And just before I reset my search text field to empty text, I want to be able to go ahead and use the 205 206 00:19:08,770 --> 00:19:11,870 searchTextField.text. 206 207 00:19:12,250 --> 00:19:21,700 So whatever the user typed in here, "to get the weather for that city," and then and only then do I've reset 207 208 00:19:21,790 --> 00:19:30,370 my searchTextField.text to an empty string. So that functionality would be the next step of building 208 209 00:19:30,370 --> 00:19:36,760 out our weather app. But let's pause for a moment because we've introduced a pretty big topic in this 209 210 00:19:36,760 --> 00:19:42,570 lesson and that's this idea of delegates and protocols. 210 211 00:19:42,640 --> 00:19:49,210 So notice how this UITextField delegate is not a class, it's not a struct, but it's something called 211 212 00:19:49,330 --> 00:19:50,820 a protocol. 212 213 00:19:50,950 --> 00:19:57,400 And to understand what protocols are and why they're so useful, head over to the next lesson where we're 213 214 00:19:57,390 --> 00:20:02,470 going to do a Swift Deep Dive on protocols and extensions. 214 215 00:20:02,710 --> 00:20:05,260 So for all of that and more, I'll see you there.