I saw in someone’s rubymotion code that it was easy to add an application icon, so I’m gonna do that to the previous app.

  • icon_iphone.png

    iPhone, 57x57 (gradient is bottom-to-top)

  • icon_ipad.png

    iPad, 72x72 (gradient is right-to-left)

  • icon_iphone_retina.png

    iPhone-retina, 114x114 (gradient is top-to-bottom)

  • icon_ipad_retina.png

    iPad-retina, 144x144 (gradient is left-to-right)

And my Rakefile becomes:

ruby Motion::Project::App.setup do |app| # Use `rake config' to see complete project settings. app.icons = ['icon_iphone.png', 'icon_ipad.png', 'icon_iphone_retina.png', 'icon_ipad_retina.png'] app.prerendered_icon = true # it's gonna look awful, btw app.name = 'thought4' app.device_family = [:iphone, :ipad] end

And on my home screen(s), we get:

  • icon_screenshot_iphone.png

    Icon demo on iPhone

  • icon_screenshot_iphone_retina.png

    Icon demo on iPhone-retina

  • icon_screenshot_ipad.png

    Icon demo on iPad

  • icon_screenshot_ipad_retina.png

    Icon demo on iPad-retina

With these, it was easy to create an icon template, I offer it here in png and pxm formats:

  • icon_template.png

    Icon Template
    png | pxm

Next up, adding a custom font. This was discussed in the #rubymotion chat room this morning, and it was super easy to implement!

  1. get your font file. .ttf is a good format to stick to. here’s one
  2. drop it in resources/
  3. It will be detected automatically, you don’t have to include it in your Rakefile, but if you did want to (because your file doesn’t end in .ttf?), it would look likes this:

    ruby Motion::Project::App.setup do |app| #... app.fonts = ["Inconsolata.ttf"] # but not necessary - all .ttf files # will be included automatically. end

  4. Use it by creating a font object, and assigning that to a font property, like on a UILabel. It’s important to use the font name, not the font filename:

    “`ruby font = UIFont.fontWithName("Inconsolata”, size:20)

    @label = UILabel.new @label.font = font @label.text = “Inconsolata font example” @label.frame = [[0, 0], [320, 30]] @label.setBackgroundColor(UIColor.clearColor);

    view.addSubview(@label) “`

I was never able to accomplish this mundane task using Xcode & Objective-C. So I think this is pretty cool stuff!

Next, let’s deal with rotation. We’ll add a button in the lower-right corner, and when the user rotates the phone, we need to move the button to the new "correct” location.

We will log the orientation to the label we just added, and we’ll need to adjust its size each time, and adjust width/height when the phone is rotated.

First, to get word wrapping enabled, add:

ruby @label.lineBreakMode = UILineBreakModeWordWrap @label.numberOfLines = 0 # any number of lines @label.sizeToFit # adjusts the height - this is an easy way to get "vertical alignment"

The button:

“`ruby @button = UIButton.buttonWithType(UIButtonTypeRoundedRect) @button.setTitle(‘Do Something’, forState:UIControlStateNormal) @button.addTarget(self, action: :resetLabel, forControlEvents:UIControlEventTouchUpInside)

I’m using a CGSize struct here, just for kicks. You can use

arrays anywhere a CGSize, CGPoint, or CGRect is expected

size = CGSizeMake(120, 35)

For example, here I mix an array for the point, and a CGSize struct for the size

@button.frame = [[320 - size.width, 440 - size.height], size] view.addSubview(@button) ”`

And the resetLabel method:

ruby def resetLabel @label.text = 'Inconsolata font example' @label.sizeToFit end

Now we will add the code that enables and responds to a rotation.

The default setting of a UIViewController is that it does not respond to a rotation. You “enable” it by returning true for other orientations:

ruby def shouldAutorotateToInterfaceOrientation(orientation) true if ipad? or orientation != UIInterfaceOrientationPortraitUpsideDown end

You’ll need the ipad? method from a previous post

Our rotation method is a CocoaTouch method, and so is superLongAndVerbose: willAnimateRotationToInterfaceOrientation(orientation, duration: duration)

“`ruby def willAnimateRotationToInterfaceOrientation(orientation, duration: duration) buttonsize = @button.frame.size # we will be moving the button, and use its # width and height as offsets buttonoffset = nil # this will hold our "starting” point case orientation when UIInterfaceOrientationPortrait, UIInterfaceOrientationPortrait append = if orientation == UIInterfaceOrientationPortraitUpsideDown ‘Upright’ else ‘UpsideDown’ end labelsize = [320, 480] buttonoffset = CGPointMake(320, 440) when UIInterfaceOrientationLandscapeLeft, UIInterfaceOrientationLandscapeRight append = if orientation == UIInterfaceOrientationLandscapeLeft ‘Left’ else ‘Right’ end labelsize = [480, 320] buttonoffset = CGPointMake(480, 300) end

@button.frame = [[buttonoffset.x - buttonsize.width, buttonoffset.y - buttonsize.height], button_size]

@label.text += “, #{append}” # resize - first, we need to set the maximum width and height again @label.frame = [[0, 0], label_size] # and then we can “sizeToFit” @label.sizeToFit end “`

The shouldAutorotateToInterfaceOrientation method checks for the iPad, and so will allow all four rotations when an ipad is used, but we are not checking for the ipad when we calculate our width/height. We should! Using code from an earlier post, let’s subclass our UIViewController and turn width, height, and margins into properties of our class (actually, we’ll write them as methods). They will return the width and height of the device when it is in portrait view.

”`ruby class MyIphoneController < MyApplicationController def width 320 end def height 480 end def marginbottom 20 end def marginright 10 end end

class MyIpadController < MyApplicationController def width 768 end def height 1024 end def marginbottom 60 end def marginright 20 end end “`

And in our AppDelegate, we will check for the device, and use the correct class.

ruby @window.rootViewController = if ipad? MyIpadController.alloc.init else MyIphoneController.alloc.init end

Change the code to use these methods. For example:


@label.frame = [[0, 0], [self.width, self.height]]

in ruby, you don’t need to use self

@label.frame = [[0, 0], [width, height]]

but I like to, because I’m coming from python

this code does the same that from above, but uses a CGPoint

point = CGPointMake(self.width - self.marginleft - size.width, self.width - self.marginheight - size.height) @button.frame = [point, size]


And so on. The full code is available in my thoughts repository

Here’s the end result, though I’m using a different font than "Inconsolata”:

  • thought4_iphone.png

    Screenshot of wrapped text on iPhone

  • thought4_ipad.png

    Screenshot of wrapped text on iPad