4
Text Input and Delegation

WorldTrotter looks good, but so far it does not do anything. In this chapter, you are going to add an instance of UITextField to WorldTrotter. The text field will allow the user to type in a temperature in Fahrenheit that will then be converted to Celsius and displayed on the interface (Figure 4.1).

Figure 4.1  WorldTrotter with a UITextField

Screenshot of the WorldTrotter app with a UITextField.

Text Editing

The first thing you are going to do is add a UITextField to the interface and set up the constraints for that text field. This text field will replace the top label in the interface that currently has the text 212.

Open Main.storyboard. Select the top label and press the Delete key to remove this subview. The constraints for all of the other labels will turn red because they were all directly or indirectly anchored to that top label (Figure 4.2). That is OK; you will fix them shortly.

Figure 4.2  Ambiguous frames for the labels

Screenshot of the interface builder canvas after deleting the first label.

Open the object library and drag a Text Field to the top of the canvas where the label you deleted was previously placed.

Now set up the constraints for this text field. With the text field selected, open the Align menu and align the view Horizontally in Container with a constant of 0. Make sure that Update Frames is set to None and then Add 1 Constraint.

Now open the Add New Constraints menu. Give the text field a top edge constraint of 8 points, a bottom edge constraint of 8 points, and a width of 250 (Figure 4.3). Add these three constraints.

Figure 4.3  Text field Add New Constraints menu

Screenshot of the Add New Constraints menu.

Finally, select the text field and the label right below it. Open the Align menu, select Horizontal Centers with a constant of 0, Update Frames for All Frames in Container, and finally Add 1 Constraint (Figure 4.4).

Figure 4.4  Aligning the text field

Screenshot of the Add New Alignment menu.

Next, customize some of the text field properties. Open the attributes inspector for the text field and make the following changes:

  • Set the text color (from the Color menu) to burnt orange.

  • Set the font size to System 70.

  • Set the Alignment to centered.

  • Set the placeholder text to be value. This is the text that will be displayed when the user has not entered any text.

  • Set the Border Style to be none, which is the first element of the segmented control with the dotted lines.

The attributes inspector for your text field should look like Figure 4.5.

Figure 4.5  Text field attributes inspector

Screenshot of the Add New Alignment menu.

Because the text field’s font changed, the views on the canvas now are misplaced. Select the gray background view, open the Resolve Auto Layout Issues menu, and select Update Frames from the All Views in View Controller section. The text field and labels will be repositioned to match their constraints (Figure 4.6).

Figure 4.6  Updated frames

Screenshot of the updated canvas. The region where the first label was placed is now replaced by a text field filled with “value” as default text.

Build and run the application. Tap on the text field and enter some text. If you do not see the keyboard, click the simulator’s Hardware menu and select KeyboardToggle Software Keyboard or use the keyboard shortcut Command-K. By default, the simulator treats your computer’s keyboard as a Bluetooth keyboard connected to the simulator. This is not usually what you want. Instead, you want the simulator to mimic an iOS device running without any accessories attached by using the onscreen keyboard.

Keyboard attributes

When a text field is tapped, the keyboard automatically slides up onto the screen. (You will see why this happens later in this chapter.) The keyboard’s appearance is determined by a set of the UITextField’s properties called the UITextInputTraits. One of these properties is the type of keyboard that is displayed. For this application, you want to use the decimal pad.

In the attributes inspector for the text field, find the attribute named Keyboard Type and choose Decimal Pad. In the same section, you can see some of the other text input traits that you can customize for the keyboard. Change both Correction and Spell Checking to No (Figure 4.7).

Figure 4.7  Keyboard text input traits

Screenshot of the keyboard text input attributes menu.

Build and run the application. Tapping on the text field will now reveal the decimal pad.

Responding to text field changes

The next step of the project will be to update the Celsius label when text is typed into the text field. You are going to need to write some code to do this. Specifically, this code will go into the view controller subclass associated with this interface.

Currently, that corresponds with the ViewController class defined in ViewController.swift. However, ViewController is not a very descriptive name for a view controller that manages the conversion between Fahrenheit and Celsius. Having descriptive type names allows you to more easily maintain your projects as they grow larger. You are going to delete this file and replace it with a more descriptive class.

In the project navigator, find ViewController.swift and delete it. Then create a new file by selecting FileNewFile... (or press Command-N). With iOS selected at the top, choose Swift File under the Source label and click Next.

On the next pane, name this file ConversionViewController. Save the file in the WorldTrotter group within the WorldTrotter project and make sure that the WorldTrotter target is checked, as shown in Figure 4.8. Click Create, and Xcode will open ConversionViewController.swift in the editor.

Figure 4.8  Saving a Swift file

Screenshot of the Save dialog box.

In ConversionViewController.swift, import UIKit and define a new view controller named ConversionViewController.

import Foundation
import UIKit

class ConversionViewController: UIViewController {

}

Now you need to associate the interface you created in Main.storyboard with this new view controller.

Open Main.storyboard and select the View Controller, either in the document outline or by clicking the yellow circle above the interface.

Open the identity inspector, which is the third tab in the utilities view (Command-Option-3). At the top, find the Custom Class section and change the Class to ConversionViewController (Figure 4.9). (You will learn what all of this is doing in Chapter 5.)

Figure 4.9  Changing the custom class

Screenshot of the Custom Class section listing two data fields: Class and Module are shown in spin boxes.

You saw in Chapter 1 that a button can send events to a controller when the button is tapped. Text fields are another control (both UIButton and UITextField are subclasses of UIControl) and can send an event when the text changes.

To get this all working, you will need to create an outlet to the Celsius text label and create an action for the text field to call when the text changes.

Open ConversionViewController.swift and define this outlet and action. For now, the label will be updated with whatever text the user types into the text field.

class ConversionViewController: UIViewController {

    @IBOutlet var celsiusLabel: UILabel!

    @IBAction func fahrenheitFieldEditingChanged(_ textField: UITextField) {
        celsiusLabel.text = textField.text
    }
}

Open Main.storyboard to make these connections. The outlet will be connected just as you did in Chapter 1. Control-drag from the Conversion View Controller to the Celsius label (the one that currently says 100) and connect it to the celsiusLabel.

Connecting the action will be a little different because you want the action to be triggered when the editing changes.

Select the text field on the canvas and open its connections inspector from the utility pane (the right-most tab, or Command-Option-6). The connections inspector allows you to make connections and see what connections have already been made.

You are going to have changes to the text field trigger the action you defined in ConversionViewController. In the connections inspector, locate the Sent Events section and the Editing Changed event. Click and drag from the circle to the right of Editing Changed to the Conversion View Controller and click the fahrenheitFieldEditingChanged: action in the pop-up menu (Figure 4.10).

Figure 4.10  Connecting the editing changed event

Screenshot shows the action of connecting the “editing changed” event to the Conversion View Controller.

Build and run the application. Tap the text field and type some numbers. The Celsius label will mimic the text that is typed in. Now delete the text in the text field and notice how the label seems to go away. A label with no text has an intrinsic content width and height of 0, so the labels below it move up. Let’s fix this issue.

In ConversionViewController.swift, update fahrenheitFieldEditingChanged(_:) to display ??? if the text field is empty.

@IBAction func fahrenheitFieldEditingChanged(_ textField: UITextField) {
    celsiusLabel.text = textField.text

    if let text = textField.text, !text.isEmpty {
        celsiusLabel.text = text
    } else {
        celsiusLabel.text = "???"
    }
}

If the text field has text and that text is not empty, it will be set on the celsiusLabel. If either of those conditions are not true, then the celsiusLabel will be given the string ???.

Build and run the application. Add some text, delete it, and confirm that the celsiusLabel is populated with ??? when the text field is empty.

Dismissing the keyboard

Currently, there is no way to dismiss the keyboard. Let’s add that functionality. One common way of doing this is by detecting when the user taps the Return key and using that action to dismiss the keyboard; you will use this approach in Chapter 14. Because the decimal pad does not have a Return key, you will allow the user to tap on the background view to trigger the dismissal.

When the text field is tapped, the method becomeFirstResponder() is called on it. This is the method that, among other things, causes the keyboard to appear. To dismiss the keyboard, you call the method resignFirstResponder() on the text field. You will learn more about these methods in Chapter 14.

For WorldTrotter, you will need an outlet to the text field and a method that is triggered when the background view is tapped. This method will call resignFirstResponder() on the text field outlet. Let’s take care of the code first.

Open ConversionViewController.swift and declare an outlet near the top to reference the text field.

@IBOutlet var celsiusLabel: UILabel!
@IBOutlet var textField: UITextField!

Now implement an action method that will dismiss the keyboard when called.

(In the code above, we included existing code so that you could position the new code correctly. In the code below, we do not provide that context because the position of the new code is not important so long as it is within the curly braces for the type being implemented – in this case, the ConversionViewController class. When a code block includes all new code, we suggest that you put it at the end of the type’s implementation, just inside the final closing brace. In Chapter 15, you will see how to easily navigate within an implementation file when your files get longer and more complex.)

@IBAction func dismissKeyboard(_ sender: UITapGestureRecognizer) {
    textField.resignFirstResponder()
}

Two things are still needed: The textField outlet needs to be connected in the storyboard file, and you need a way of triggering the dismissKeyboard(_:) method you added.

To take care of the first item, open Main.storyboard and select the Conversion View Controller. Control-drag from the Conversion View Controller to the text field on the canvas and connect it to the textField outlet.

Now you need a way of triggering the method you implemented. You will use a gesture recognizer to accomplish this.

A gesture recognizer is a subclass of UIGestureRecognizer that detects a specific touch sequence and calls an action on its target when that sequence is detected. There are gesture recognizers that detect taps, swipes, long presses, and more. In this chapter, you will use a UITapGestureRecognizer to detect when the user taps the background view. You will learn more about gesture recognizers in Chapter 19.

In Main.storyboard, find Tap Gesture Recognizer in the object library. Drag this object onto the background view for the Conversion View Controller. You will see a reference to this gesture recognizer in the scene dock, the row of icons above the canvas.

Control-drag from the gesture recognizer in the scene dock to the Conversion View Controller and connect it to the dismissKeyboard: method (Figure 4.11).

Figure 4.11  Connecting the gesture recognizer action

Screenshot of the Tap Gesture Recognition menu.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset