RubyMotion Blog


This is the official blog of RubyMotion, a toolchain for iOS, OS X and Android development that lets you do iPhone, iPad, Mac and Android apps in Ruby.

Follow us on Twitter to stay tuned with everything that's happening in the community!

Not a RubyMotion user yet? Give it a spin today!

Introducing ProMotion, a Full-Featured RubyMotion Application Framework

(This is a guest post from Jamon Holmgren, creator and maintainer of ProMotion)

Last August I started working on a new RubyMotion app. I quickly realized that one of UIKit’s most frequent pain points is working with UINavigationControllers, UITabBarControllers, and UIViewControllers — it just took too many lines of code to move around in my app. That led to the idea behind ProMotion: abstracting the screen and navigation handling in a Ruby-like way.

It has been a great experience building it and I’m going to show you how ProMotion could make your next iOS project a lot easier (with lots of code examples!). The source is also available on GitHub.

Screens: Ruby-like UIViewControllers

ProMotion subclasses UIViewController and UITableViewController to provide a ton of new functionality and abstraction and calls them ProMotion::Screen. (You can also use ProMotion with Formotion or your own UIViewController).

Note: from now on I’ll refer to ProMotion by its shortcut alias, PM.

class HomeScreen < PM::Screen
  title "Home"

Pretty simple. What about viewWillAppear:animated and other Obj-C methods? We implement simpler versions of those for your use:

def on_init
# Fires right after the screen is initialized

def on_load
# Fires just before a screen is added to a view for the first time.

def will_appear
# Fires every time the screen will appear

def on_appear
# Fires just after the screen appears somewhere (after animations are complete)

def will_disappear
# Fires just before the screen will disappear

def on_disappear
# Fires after the screen is fully hidden
Invisible UINavigationControllers

When you create a screen you can pass in attributes. One of these is nav_bar: true which creates a UINavigationController and pushes the screen onto it. You don’t have to manage the navigation controller at all.

open true)

Within that screen you can open other screens and they’ll be pushed onto the UINavigationController automatically.

open SecondaryScreen

If you pass in a class instead of an instance, ProMotion will instantiate it for you.

Easy TabBarControllers

Opening and managing a UITabBarController is a pain in Objective-C. ProMotion makes it very simple and natural.

class AppDelegate < PM::Delegate
  def on_load(app, options)
    open_tab_bar HomeScreen, AboutScreen, ContactScreen, HelpScreen

# in app/screens/home_screen.rb

class HomeScreen < PM::Screen
  def open_another_tab
    # Switches to the AboutScreen created above if its tab title is “About”.
    open_tab “About”

  def open_new_screen_in_another_tab
    # Programmatically switches to the HelpScreen
    # and pushes the SecondaryScreen onto its UINavigationController.
    open SecondaryScreen, in_tab: “Help”
Smart SplitViewControllers

Split view controllers are as easy as tab bars.

open_split_screen MenuScreen, DetailScreen

open split screen

From the left-hand part of the split screen it’s easy to open a child screen in the right. Just add in_detail: true to the open command:

open SomeDetailScreen, in_detail: true

This is ignored if there isn’t a split screen so it’s ideal for use in universal apps.

Effortless Table Screens

You can easily build list views (“tables”) in ProMotion. Formotion is excellent for building forms, but sometimes you just want a menu or list of information. That’s where ProMotion’s built-in TableScreen works well.

class HelpScreen < PM::GroupedTableScreen
  title "Help"

  def table_data
    @help_table_data ||= [{
      title: "Get Help",
      cells: [{
        title: "Email us", action: :email_us

  def email_us
    mailto_link = NSURL.URLWithString("")

When the Email us cell is tapped, ProMotion fires the email_us method.

table screen

For plain tables, you can add searchable and refreshable easily:

class StatesScreen < PM::TableScreen
  title “States”

  def table_data
    # list of states

  def on_refresh
    # refresh your data here, usually async
    some_async_call do
      # update your data

searchable, refreshable list of states

Styling with Style

Everybody has their favorite iOS styling system and ProMotion works beautifully with all of them. Pixate, NUI, and of course RubyMotion’s Teacup are all very good choices.

For those who want a simple, Teacup-lite styling system, ProMotion comes with one built-in.

set_attributes self.view,
  background_color: UIColor.grayColor

add UILabel.alloc.initWithFrame([[10, 10], [300, 45]]),
  text: “Welcome to ProMotion!”,
  resize: [ :left, :right, :top ],
  background_color: UIColor.clearColor,
  text_color: UIColor.whiteColor,
  shadow_color: UIColor.blackColor,
  number_of_lines: 0,
  text_alignment: UITextAlignmentCenter,
  font: UIFont.boldSystemFontOfSize(18.0)

This UILabel is added to the view and all the attributes are set. Snake case is converted to camel case automatically when appropriate. There are also some nice helpers like the resize setting for UIViewAutoresizingMasks.


Perfect for Production

ProMotion is already being used in production apps around the world and is becoming quite stable. It’s likely that version 1.0 will be coming soon without major changes to the API.

Without RubyMotion, it’s very unlikely that a system like ProMotion would exist. There’s nothing like it in the Objective-C world and the community is a lot different there. It’s a testament to the RubyMotion community as well as Laurent and his team for making this possible.

This is just an intro to ProMotion — head over to the GitHub repo to learn more. I hope you take a look at it for your next project!

Jamon Holmgren (@jamonholmgren) is the owner of ClearSight Studio, a mobile app and web development studio located near Portland, OR.

Interested in giving RubyMotion a try? We offer a 30 days money back guarantee. Download it today!
Follow us on Twitter to stay tuned with everything that is happening in the community.

By Laurent Sansonetti.