This post shows you how to make an app that has the following flow:
Here’s a video of it
I’m assuming that you are comfortable with Ruby.
require
autoload
define_method
and a few more. So most of your rubygems turnout to be useless, unless you hack them bit.
UI elements in iOS have a frame. Think of it as the frame for a photograph on your wall. When you create elements, you have to specify the frame, in the following format:
[[x, y], [width, height]]
You’ll be using the following UI elements
iOS documentation is available here - http://developer.apple.com/library/ios/navigation/
Don’t hesitate to copy-paste code to try out things. That is exactly why code snippets are for. Go even further and make your own modifications.
I learnt RubyMotion a few hours before making this app and have never written an iOS app as of this blog post. So if you find something can be done in a better way, share your suggestions.
This post is a bit lengthy because of the basics. So just hang on and the pastures on your side will turn green. Let’s create a new application using the motion
command
$ motion create click_to_greet
Create click_to_greet
Create click_to_greet/.gitignore
Create click_to_greet/Rakefile
Create click_to_greet/app
Create click_to_greet/app/app_delegate.rb
Create click_to_greet/resources
Create click_to_greet/spec
Create click_to_greet/spec/main_spec.rb
cd
into the click-to-greet
directory. All relative paths mentioned from now on will be relative to this directory.
All your code must go into the app
directory. This is how your app/app_delegate.rb
looks like when your app is first generated:
class AppDelegate
def application(application, didFinishLaunchingWithOptions:launchOptions)
true
end
end
The pattern is similar to the MVC pattern. And this app_delegate.rb is like the Rails routes file. It’s used to set the root controller for your application.
This the order of elements in the iOS UI.
UIScreen (the screen)
|
|__UIWindow (the window)
|
|__UIViewController
|
|__UIView (generally UI elements)
First, create a window for the application. And also set the root controller for it. Right now it’s just some class name and we’ll call it MainViewControler
. So your app_delegate.rb
should look like the following.
class AppDelegate
def application(application, didFinishLaunchingWithOptions:launchOptions)
# Get the frame for the window
@window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
# Instantiate a new object of the MainViewController
# and assign it as the root controller.
@window.rootViewController = MainViewController.new
# This makes the window a receiver of events (for now we are using touch).
@window.makeKeyAndVisible
# Because this method must return true
true
end
end
Just like in Ruby, to instantiate an object of a class, you use the Class.new
method. In iOS, you have to allocate memory to the object first and then initiate it. In RubyMotion, the Class.new
method does the same as Class.alloc.init
iOS provides some helper class methods that allows you to do some tasks in a shorter way. So instead of instantiating an object and then assigning a frame to it like below.
@window = UIWindow.new
@window.frame = UIScreen.mainScreen.bounds
iOS provides the initWithFrame
on UI elements. But this must be used with the alloc method, which is why you see:
@window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
UIScreen.mainScreen.bounds
returns the frame, that the main screen provides for applications.
Now for the MainViewController
, create the file app/main_view_conroller.rb
.
# You have to inherit from UIViewController
class MainViewController < UIViewController
# Called to load the view
# This is where you instantiate your view and set it as the controller's view.
def loadView
# Set the view for the controller
# We don't need anything special for now. So we'll directly instantiate an object of UIView
self.view = UIView.new
end
# Called after the view is loaded
def viewDidLoad
# A text input field instantiated with initWithFrame
@input_field = UITextField.alloc.initWithFrame([[0, 0], [200, 40]])
# Set the text color using the UIColor class which offers named colors
@input_field.textColor = UIColor.blackColor
# Set the background color for the text field
@input_field.backgroundColor = UIColor.whiteColor
# Set the border style of the text field to rounded rectangle
# We need a rounded border, defined by the constant UITextBorderStyleRoundedRect
@input_field.setBorderStyle UITextBorderStyleRoundedRect
# Add the text field to the controller's view
self.view.addSubview @input_field
# Initiate button with button type
@action_button = UIButton.buttonWithType UIButtonTypeRoundedRect
# Set the title for the default UI state, which is normal
# Normal UI state is defined by the constant UIControlStateNormal
@action_button.setTitle "Greet me", forState: UIControlStateNormal
# Set the frame for the button
@action_button.frame = [[100, 100], [100, 50]]
# Add an event for the button when touched
# 'self' refers to the handler class for the action in which the callback is defined
# greet_user is the method is that'll be called when the event happens
# The touch state is defined by the constant UIControlEventTouchUpInside
@action_button.addTarget(self,
action: :greet_user,
forControlEvents: UIControlEventTouchUpInside)
# Add the button to the view
self.view.addSubview @action_button
end
# The touch callback for the button
def greet_user
# Instantiate an alert box with the title and a greeting message
# And a text for the cancel button
# Which will say "ok"
# The arguments from the second to last, are not Ruby hash arguments
# They are Objective-C style arguments.
# You can't randomize the order or skip them if they are nil
@alert_box = UIAlertView.alloc.initWithTitle("Greeting",
message:"Hi #{@input_field.text}",
delegate: nil,
cancelButtonTitle: "ok",
otherButtonTitles:nil)
# Show it to the user
@alert_box.show
end
end
Now that you’ve typed out the stuff required, run the rake
command in the project’s directory. The iOS simulator should popup and showcase your app in all glory.