"Time is precious; waste it wisely."
–Anonymous
In this chapter we will learn about some features of iOS development with RubyMotion. Xcode is a very advanced IDE and has many qualities, which we can exploit to develop faster and better iOS applications. In this chapter we will also learn how to use an Interface Builder for rapid development with RubyMotion. We will also have a look at some key elements of Xcode, such as .xib
, .nib
, and WebView, to create real-life interactive apps.
Xcode's Interface Builder allows you to create your application's user interface visually, instead of writing code. Interface Builder is a great tool that is very simple to use and is pivotal in making iOS development really fast. Therefore, the Interface Builder used along with RubyMotion further reduces development time. We can say these are two delicious recipes independently, but when used together, it's the ultimate formula to make beautiful iOS apps as quickly as possible.
Interface Builder comes with Xcode. Before we jump into using Interface Builder, it's important to understand that although Interface Builder creates the UI using the drag-and-drop mechanism, it is however not creating the Objective-C code behind the scene. It's creating an XML description of the GUI you're building, and the Cocoa Touch framework uses that XML to actually create the UI elements, such as label and textbox, for your application at runtime. Everything we do in Interface Builder could be done by writing lines of Ruby code—that's exactly what we have been doing from the beginning of this book—but shortly you will see how things get really easy with a GUI builder.
Before we begin using Interface Builder, let's understand some jargon associated with XCode development. The GUI builder provides options to drag-and-drop buttons, table views, and text fields into your app window. The resulting interface is stored as a .xib
file. A .xib
file is an XML representation of your objects and their instance variables, and it is compiled into a .nib
file when your application is built. The .xib
file is easier to work with but the .nib
file is smaller and easier to parse, that's why the file that actually ships with your application is a .nib
file.
So far we have created the views for our Restro application views by writing code in Ruby. In this section, let's create a view using the GUI-based Interface Builder. We will create a Contact Us form and use it in our application.
The Interface Builder is integrated into Xcode, which is a one stop IDE for any Apple-related development, whether it's for iOS devices or Mac. We will create a .xib
file and then use this file in our RubyMotion project by performing the following steps:
.xib
file.ViewController.xib
and you will be able to see the Interface Builder.The Interface Builder has a fairly simple layout; it consists of four main windows:
The View window is where you construct your interface. You will drag-and-drop items from the Library window onto the View window to place them. The document browser allows you to browse hierarchically the elements you have placed in your .nib
file. Finally, the Inspector window shows you all of the different attributes of the selected element and allows you to edit them.
And now the magic begins; drag Navigation Bar from Library to view the section as shown in the following image:
When you select Navigation Bar, you will see many properties in the Inspector window. Change the tag value to 1 in the Inspector window. Remember that we will use this tag value in the RubyMotion project code. We need to wire our View Controller
elements. The easiest way to do this is to use its Tag attribute. Tag is an integer
property of the UIView
class that you can use to identify your views. Basically, you have to set a unique integer for each UIView
class you need to access from your UIViewController
element.
Similarly, add a text field for e-mail and change the value for the placeholder to Email
as shown in the following screenshot. There are a lot of properties associated with every Library object; for example, in case of a text field, we have changed the keyboard value to Email
as it suits our requirement; but you are free to go ahead and play with other properties too. Using Email
will show a keyboard customized for entering e-mail addresses.
Next, we need a button. Let's drag-and-drop a button onto the View window.
In this section, we will import our .xib
file into our RubyMotion project. Open the folder of the Xcode project and locate ViewController.xib
. It's inside a folder named en.lproj
; copy it into the resources
folder of your Restro application, which we created in the last chapter.
Update the about_controller.rb file
in the restro
app, which we created in the last chapter, with the following code:
def setupNavigationBar back= UIBarButtonItem.alloc.initWithTitle("Back", style:UIBarButtonItemStylePlain,target:nil ,action:nil) self.navigationItem.backBarButtonItem = back; contact_us_button = UIBarButtonItem.alloc.initWithTitle("Contact Us", style:UIBarButtonItemStylePlain ,target:self, action:"contact_us") self.navigationItem.rightBarButtonItem = contact_us_button end def contact_us contact_us_controller = ContactUsController.alloc.initWithNibName("ViewController", bundle:nil) presentModalViewController(contact_us_controller, animated:true) end
As we have imported the .xib
file from Xcode to the RubyMotion project, RubyMotion creates a .nib
file automatically when we build the code with the Rake
command. Here, we are creating a View Controller
variable with an initializer initWithNibName
that receives a parameter, which will be the name of the .nib
file. This initializer has the responsibility of instantiating the .nib
file and wiring the View
declared in the view
property of the View Controller variable
.
Create a file contact_us_controller.rb
inside the app folder as follows:
class ContactUsController < UIViewController end
Let's fire up the terminal and run the application with the following command:
$rake
The following screenshot shows the output of the preceding command:
Next, let's update contact_us_controller.rb
with the following code:
class ContactUsController < UIViewController HEADER_TAG = 1 EMAIL_BOX_TAG = 2 INFORMATION_BOX_TAG = 3 SUBMIT_BUTTON_TAG = 4 def viewDidLoad @header = self.view.viewWithTag(HEADER_TAG) @email_box = self.view.viewWithTag(EMAIL_BOX_TAG) @information_box = self.view.viewWithTag(INFORMATION_BOX_TAG) @submit_button = self.view.viewWithTag(SUBMIT_BUTTON_TAG) @submit_button.addTarget(self, action:"send_message", forControlEvents:UIControlEventTouchUpInside) tapGesture = UITapGestureRecognizer.alloc.initWithTarget(self, action:"hideKeyboard") tapGesture.cancelsTouchesInView = false view.addGestureRecognizer(tapGesture) end def send_message if form_valid? puts "Submitted the button with correct values" close else puts "Invalid Values" end end def close dismissModalViewControllerAnimated true end #method to hide keyboard when user taps on a scrollview def hideKeyboard @information_box.resignFirstResponder end def form_valid? not @email_box.text.empty? and not @information_box.text.empty? and not @email_box.text.match(/A([^@s]+)@((?:[-a-z0-9]+.)+[a-z]{2,})/i).nil? end end
Let's start the application by using the following command:
$rake
Enter a few incorrect values in the form and you will get Invalid value printed on the terminal. Once you enter the values correctly in the form and submit it, it will be pulled down.
Now let's understand the code. First we have assigned the tags to the attributes that we had created in Interface Builder. And then we have used these tags to wire our variables to those components.
self.view.viewWithTag(HEADER_TAG)
The preceding command will retrieve a subview of self.view
based on its tag.
We have also created an action
item for the Submit button. That means when we click on the Submit button, it will call the action send_message
.
@submit_button.addTarget(self, action:"send_message", forControlEvents:UIControlEventTouchUpInside)
In the send_message
action, we are checking whether the form is valid or not.
Some developers like to design the user interface using Interface Builder; others prefer to work entirely with code. One of the reasons is that when connecting Interface Builder outlets and actions to your code, it is easy to make a mistake. This often results in an error that is more difficult to debug than if you had simply written the entire code, as you have to debug in two places (Interface Builder and your code) instead of just one (the code).
3.15.17.28