A quick introduction to Teacup

Conrad Irwin — June 2012

Teacup is a library for RubyMotion that let's you create views and layouts in simple declarative code. The simplest way to understand it is that it's "CSS for iOS", but that would be to heavily underestimate what it can do. Perhaps a better analogy is "Interface Builder for RubyMotion", as both tools solve the same problem.

Creating layouts

Once you've added teacup to your app, you can get started immediately by creating views in your controller:

class MyViewController < UIViewController
  attr_accessor :button

  layout do
    subview UILabel,
      text: "Hello World"

    self.button = subview(
      UIButton.buttonWithType(UIButtonTypeCustom),
      title: "Click me!"
    )
  end
end

Now, whenever MyViewController is shown, it will contain both a label and a button. You'll also notice that I've stashed the button away on self.button so that I can refer to it later in the controller. I won't need to use the label in my code, so I can just rely on the view heirarchy to retain it as necessary.

Making them pretty

Unfortunately the code in the previous section had a bit of a flaw; when you run it the label and the button don't actually appear. This is because Cocoa defaults all elements to zero width and zero height, and is really easy to fix:

class MyViewController < UIViewController
  attr_accessor :button

  layout do
    subview(UILabel,
      text: "Hello World",
      top: 60, left: 60,
      width: 200, height: 100,
      backgroundColor: UIColor.blueColor
    )

    self.button = subview(
      UIButton.buttonWithType(UIButtonTypeCustom),
      title: "Click me!",
      top: 200, left: 60,
      width: 200, height: 100
    )
  end
end

Again this hopefully stating the obvious, but I should now have a blue label a short distance from the top of the screen and a button just underneath that. Both of them are 60px from the left and 200px wide so that they appear centered.

Stylesheets

While the code in the previous section works just fine, it's somewhat ugly on two fronts. The most obvious issue is that if I want to change the left margin I have to do that in multiple places, but also my controller is being filled with irrelevant details. It really doesn't matter what size the button has, from a controller's point of view, that's a view-level concern.

To solve these problems teacup provides you with stylesheets:

# app/controllers/my_view_controller.rb
class MyViewController < UIViewController
  attr_accessor :button

  stylesheet :iphone

  layout do
    subview(UILabel, :hello_world)
    self.button = subview(UIButton, :click_me)
  end
end
# style/iphone.rb
Teacup::Stylesheet.new :iphone do
  style :widget,
    left: 60,
    width: 200,
    height: 100

  style :hello_world, extends: :widget,
    text: "Hello World",
    top: 60,
    backgroundColor: UIColor.blueColor

  style :click_me, extends: :widget,
    title: "Click me!",
    top: 200
end

This new code solves both of the code structure problems; the nitty-gritty of making the view look right is no-longer polluting the controller, and the left-margin is only specified in one place due to use of the extends: meta-property.

Further reading

This blog post has just scratched the surface of what's available in teacup. To get full information you should read the API docs for Stylesheets and for the layout function.

To get the example code created in this blog post you can clone the git repository. Other example uses of teacup can be found in the sample app that's included with teacup itself, and the Commune app which is where some of the initial experiments were done.

If you are having problems or want to help us improve teacup, please join in on GitHub or in #teacuprb on Freenode.