iOS SDK: Creating a Custom Text Input View

Developing an amazing application is not a simple job. Traditionally, one of the most difficult aspects of doing so has been creating rich, compelling interfaces. This tutorial will teach you how to build a custom text input view that will help make your own apps shine!


Tutorial Preview



Series Overview

This tutorial is the first in a collection on building custom interface elements. In this tutorial, we will cover customized text input views, and in the next two tutorials we will go over custom accordion menus and alert views. The series format is as follows:

In this tutorial we are going to create a simple list application, which will incorporate some basic features. In this example, our app will only be able to add and edit items using our brand new custom text input view. The final project of this tutorial is going to be the base for the next one, where we are going to create an accordion menu to provide the user with some options. In the third and last tutorial, we will use the final project of the second tutorial to create a custom alert view.


1. Create the Project

Begin by launching the Xcode and create a Single View Application:

Proceed and set a name for the project. I named mine CustomViewsDemo. Make sure to check on the Use Automatic Reference Counting option as well:

Finally, select a folder to save the project and click Create:


2. Setup the Interface

Step 1

Click on the ViewController.xib file to let the Interface Builder show up on the screen. First, turn off the Autolayout option (we do this to let this demo project work on iOS older than 6 - Autolayout is an iOS 6 feature):

  • Click on the Utilities button at the Xcode toolbar to show the Utilites pane, if it is not visible.
  • Click on the File Inspector.
  • Scroll towards the bottom a little bit and click on the Use Autolayout option to turn it off.

Step 2

Now click on the Attributes Inspector and under the Simulated Metrics section set the Size value to None, so that it works on a 3.5" screen as well.

Step 3

Add a UIToolBar into the view and place it at the bottom of the view. Do the following:

  • Add a Flexible Space Bar Button Item to the left of the default bar button item to force it to stay on the right side of the toolbar.
  • Set the title of the bar button item to Add item.
  • Set the Tint Color of the button to: (R: 51, G: 51, B: 51).
  • Set the Tint Color of the toolbar to (R: 0, G: 0, B: 51).

Step 4

Next, add a UITableView inside the remaining available space of the view. Set its style to Grouped and the separator to Single Line:

Also, set its background color to (R: 51, G: 51, B: 51). Your interface should now look like this:


3. IBOutlet Properties & IBAction Methods

Before going any further we need to connect the UITableView to an IBOutlet property and create an IBAction method for the toolbar's bar button item (the "Add item" button"). In order to do this, while in Interface Builder, click on the middle button of the Editor section on the Xcode toolbar to reveal the Assistant Editor:

Step 1

To insert a new IBOutlet property, Control+Click (Right click) on the Table View > Click on the New Referencing Outlet > Drag and Drop into the Assistant Editor.

Next specify a name for the new property. I simply named it table.

Step 2

To create an IBAction for the bar button item, Control+Click (Right click) on the Bar Button item > Click on the Selector option in the Sent Actions section > Drag and Drop into the Assistant Editor:

Set a name for the method. I named mine addItem.


4. UITableView Methods

Step 1

In this step we need to implement the minimum required table view methods in order for our table to work correctly. But before we do that, we need to set the view controller as the delegate and datasource for the table view.

Click on the ViewController.h file. Form the @interface header as follows:

Then inside the ViewController.m file and in the viewDidLoad method add the following:

Step 2

A NSMutableArray array will be the source of our list items (the table's contents). First, however, we need to declare and initialize it. Inside the ViewController.m file, go to the top of it and inside the private part of the @interface add the next line:

Also inside the viewDidLoad:

Step 3

Let's now implement some methods of the table view. We'll begin with the number of sections:

Next set the total number of rows. This number is equal to the total objects existing in the _sampleDataArray array.

Let's set the height of each row:

Now, let's setup our cells. Inside the code you'll find all the customization for the cells. There are comments explaining almost everything. You may change whatever you desire at your own will:

Finally, add the -(void)tableView:didSelectRowAtIndexPath: delegate method:

Right now leave this method blank. We will visit it again later.

To summarize so far, we have created our project and setup the interface using the Interface Builder. We connected the necessary IBOutlet property and IBAction method and implemented the minimum required methods in order to make our table (our list) to properly work. Let's progress to create the custom text input. We will get back to the ViewController in a little bit.


5. Custom Text Input View Controller

When developing projects, it is a nice habit to keep everything tidy and in order. For this reason, we will create a new group (a virtual folder) for the text input view controller.

Step 1

On the Project Navigator pane on the left side of the Xcode, Control+Click (Right click) on the CustomViewsDemo group > Select the New Group option from the popup menu:

Name the new group Custom Text Input View:

Step 2

Now we're ready to add the new view controller. Control+Click (Right click) on the CustomViewsDemo group > Select the New File... option from the popup menu:

As the template for the new file select the Objective-C class and click Next.

Give the name CustomTextInputViewController in the class field and make sure that in the Subclass of field the UIViewController value is selected. Also, don't forget to set the With XIB for user interface option checked:

Finally, click on the Create button. Make sure that the Custom Text Input View is the selected group, as shown in the following image:


6. Text Input View's Interface

Step 1

Click on the CustomTextInputViewController.xib file to reveal the Interface Builder and setup the interface. Do the following:

  • Just as we did earlier, turn the Autolayout option off (Utilities Pane > File Inspector > Click on the Use Autolayout checkbox).
  • Click on the Attributes Inspector and under the Simulated Metrics section change the Size to None.

Step 2

Now it's time to add the desired subviews into our view. Add the next subviews and set their properties as described:

  1. UILabel
    • Frame: X: 0.0, Y: 145.0, Width: 320.0, Height: 30
    • Font:: Georgia, 17.0
    • Color:: Black
    • Alignment:: Center
    • Background Color: (R: 204, G: 204, B: 204)
  2. UITextField
    • Frame: X: 0.0, Y: 180.0, Width: 320.0, Height: 30.0
    • Font: Georgia, 15.0
    • Color: Black
    • Border Style: Bezel
    • Clear button: Appears while editing
    • Capitalization:Sentences
    • Return Key: Done
    • Background Color: White

    Most of these settings will appear in the next image:

  3. UIToolBar
    • Frame: X: 0.0, Y: 225.0, Width: 320.0, Height: 44.0
    • Tint Color: (R: 204, G: 204, B: 204)

Note that the Y point is not important right now as it's going to be set programmatically for every subview.

Step 3

Apart from the above, add the following UIBarButton items to the toolbar next to the default bar button item:

  • A flexible space bar button item
  • Another bar button item

Select both of the bar button items (not the flexible space item) and set their color to (R: 51, G: 51, B: 51). For the left bar button, set the title to Okay. For the right bar button, set the title to Cancel.

Finally, select all three subviews (UILabel, UITextField, and UIToolBar) and set the Autosizing values as shown below (Flexible Width, Flexible Right Margin, Flexible Left Margin, and Flexible Bottom Margin):


7. IBOutlets & IBActions

I previously showed you how to create IBOutlet properties and IBAction methods and how to connect them to subviews. Following the same method as described above, create and connect the next properties to the UILabel, UITextField, and UIToolbar respectively:

Then go to declare and connect the next IBAction methods to the Okay and Cancel buttons:

At this point our job with the Interface Builder is over. It's time to code the behavior that we require from the text input view.


8. Coding

Step 1

First, we need to make some kind of setup in the code, prior to implementing any method. We will begin by setting the view controller as the delegate for the textfield. Click on the CustomTextInputViewController.h file and modify the @interface header according to this:

Next, go to the CustomTextInputViewController.m file and inside the viewDidLoad method set the delegate:

Also, inside the viewDidLoad set the UIToolbar (the toolbarIAV) as the Input Accessory View of the textfield:

So far, so good. At the beginning of this tutorial, I mentioned that the view of the view controller will work as a cover with the goal to prevent users from tapping anything else existing behind our view. We also need it to be semi-transparent too, so that it looks good. Therefore, go and add the next line that configures our view:

Now let's think about it. As we said at the beginning, we need the textfield to appear just right above the input accessory view (the toolbar) and the title label above the textfield. To achieve this layout, we need to know the origin of the keyboard and the input accessory view, so we can adjust the textfield and the label accordingly. But how do we know when the keyboard appears and how do we get its size or its origin?

Well, the answer is simple. Each time the keyboard is about to appear, iOS sends a notification, named UIKeyboardWillShowNotification (actually, the iOS sends more notifications but we don't care about them right now). We will add the view controller as an observer for this notification and when it arrives a predefined method (by us) is going to be called. With this in mind, add the next line, again into the viewDidLoad method:

Note that the keyboardWillShowWithNotification: is a method that we'll implement in a while.

Another point that we should take into consideration is the status bar. The position where our subviews appear depend on the status bar and its height. Therefore, it would be a good idea if we had a variable that keeps the offset created by the status bar (its height) when it's visible.

Go to the top of the file and inside the private part of the @interface declare a CGFloat variable that will represent the status bar offset. Along with that declare the keyboardWillShowWithNotification: I mentioned a little bit earlier:

I'll mention ore about the status bar soon.

Step 2

Now we are ready to proceed to the implementation phase and we can create the necessary public methods that can be accessed by other classes. Go to the CustomTextInputViewController.h file and declare the following three methods:

It should be clear what each method will do.

Let's begin with the showCustomTextInputViewInView:withText:andWithTitle method. Before we begin coding, there are a few points that I should mention. First of all, we need to check whether the status bar is visible or not and set the statusBarOffset value appropriately. We can easily find out if it's visible and get its size. However, there is a small trap in case the status bar is visible and we have to deal with both portrait and landscape orientation. In portrait mode the status bar size is in the form Width x Height (e.g. 320.0 x 20.0). In landscape mode the size is in the form Height x Width (e.g. 20.0 x 480.0). The easiest way for us to determine the status bar height is to check the minimum value between the width and the height. With this method it is certain that we will get the correct value. Add these right after into the code snippet that follows.

Additionally you may remember we turned the Autolayout feature off, so we are responsible for presenting our views correctly in all orientations. This means that we have to check the orientation every time this method is called and set the view's frame accordingly. It is important to note that when we are in landscape mode the width of the screen is the height for the view and the height of the screen is the width for the view. Also because the status bar is visible, a padding is created at the left side of the view in landscape mode, which needs to be eliminated. That's partially why we declared the statusBarOffset variable earlier.

Finally, we want our view to be out of sight at the beginning and animations to smoothly slide into the screen.

But first let's see everything in action. Open the CustomTextInputViewController.m and implement the method:

The comments inside the method explain everything. Note that inside it we call the becomeFirstResponder method of the _txtText textfield, so that the keyboard will appear too. We'll see in a while how important this call is, as that's the key point for our views to be positioned correctly.

Now, let's implement the next method. The closing of the view is the opposite action from the showing.

Note that we removed the view from the superview not at once but after the animation is over.

Finally, the third method:

Step 3

This next step will show you how to handle the keyboard. Earlier inside the private part of the interface we declared this method:

This is the method that will be called every time the keyboard is about to appear and a UIKeyboardWillShowNotification notification will arrive. Now we can start working on it. The notification parameter contains a NSDictionary with information regarding the keyboard. A piece of that information is the keyboard's size and origin. What we actually need here is the origin point because if we know the Y coordination of the keyboard (input accessory view included), we can properly layout the textfield and the label. Once more, in landscape mode it changes and the keyboard's X coordination is the desired Y coordination for our textfield. Here is the code you'll need:

I am sure that you have noticed the subtraction of the statusBarOffset in the code above. If we don't do that the textfield will hide under the input accessory view.

Step 4

At this phase we need to work on the protocol definition. Up to this point the view controller is almost ready, but not completely finished. What is missing here is the protocol definition which allows the delegate class that adopts it (in our case the ViewController) to implement the necessary methods required to handle the Okay and Cancel button taps.

Go to the CustomTextInputViewController.h file and define a protocol, along with the next delegate methods:

Also, right after the @interface header, add the highlighted line:

According to what we have done, the delegate class should implement the shouldAcceptTextChanges method in order to handle the Okay button tapping and the shouldDismissTextChanges method in order to handle the Cancel button tapping.

But, what about the IBAction methods of this class? They have been left blank until now. Let's now fill them in:

As you can see, when the Okay button is tapped the shouldAcceptTextChanges delegate method is called, while when the Cancel button is tapped the shouldDismissTextChanges delegate method is called.

In order to be entirely correct, there is one more step to complete: make the Done button of the keyboard work. To do this, we just need to implement the -(BOOL)textFieldShouldReturn: delegate method:

Now our new custom view is ready. All we need to do is try it out.


9. Text Input View in Action

Step 1

Before we see our new custom text input view working, there are a few more steps we need to complete. First of all, we should declare the ViewController class as its delegate. Open the ViewController.h file, import the CustomTextInputViewController.h file and make our class its delegate at the interface header:

Now turn to the ViewController.m file and inside the private part of the @interface declare a CustomTextInputViewController object. I named it textInput:

Let's initialize it inside the viewDidLoad method:

Step 2

Go to the addItem IBAction method to make our text input view appear:

Simple, right?

If you run the app now, you'll see the text input view in action, but the Okay and Cancel buttons won't work because we haven't implemented the delegate methods yet. So, let's do it now:

Run it and it will work. Any text you enter into the textfield will appear in the table. But we are not completely ready because we are unable to edit any items.

Step 3

It's time to visit the table view's delegate method -(void)tableView:didSelectRowAtIndexPath:. We want each row that is tapped to be edited in our custom text input view. But we also need to know when the user adds or edits a row. For that reason, we will use a flag that will indicate whether the user edits a row or not.

Go to the private part of the @interface and add the following variable:

Don't forget the curly brackets. Now into the viewDidLoad method set its value to NO.

Move to the table's delegate method:

At this point, when you tap on existing rows on the table view, the text input view will appear to edit them. But no matter how hard you try, your changes will not be saved into the edited row, instead they will be saved as new rows. That means that we have to slightly modify the -(void)shouldAcceptTextChanges delegate method as such:

Remember that when editing a row's content, the equivalent object inside the sample data array is replaced. Also, pay attention to the isEditingItem. It gets the NO value again.

Now everything is ready to work. Run the app and test it in both portrait and landscape orientation.


Conclusion

As you may have realized, sometimes it is worthwhile to create custom views that serve your needs better than the standard iOS SDK views. The custom text input view is a reusable component with little or no modification. It can be used in many projects, and we've done all of it using simple techniques and programming principles. This custom text input view, now at everyone's disposal, can be a subject for further customization and improvements, and hopefully it will be useful for many programmers! In the next tutorial we'll use this project and we will add a new feature, an accordion menu with options provided to the user. But for now enjoy the custom text input view!

Tags:

Comments

Related Articles