Poking around with this and that on rubymotion a rubymotion thought by colinta
View the source at github.com/colinta/thoughts
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.
And my Rakefile becomes:
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:
With these, it was easy to create an icon template, I offer it here in png and pxm formats:
Next up, adding a custom font. This was discussed in the #rubymotion chat room this morning, and it was super easy to implement!
- get your font file.
.ttfis a good format to stick to. here's one - drop it in resources/
- 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:
Motion::Project::App.setup do |app| #... app.fonts = ["Inconsolata.ttf"] # but not necessary - all .ttf files # will be included automatically. end
- 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:
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:
@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:
@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:
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:
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)
def willAnimateRotationToInterfaceOrientation(orientation, duration: duration) button_size = @button.frame.size # we will be moving the button, and use its # width and height as offsets button_offset = nil # this will hold our "starting" point case orientation when UIInterfaceOrientationPortrait, UIInterfaceOrientationPortrait append = if orientation == UIInterfaceOrientationPortraitUpsideDown 'Upright' else 'UpsideDown' end label_size = [320, 480] button_offset = CGPointMake(320, 440) when UIInterfaceOrientationLandscapeLeft, UIInterfaceOrientationLandscapeRight append = if orientation == UIInterfaceOrientationLandscapeLeft 'Left' else 'Right' end label_size = [480, 320] button_offset = CGPointMake(480, 300) end @button.frame = [[button_offset.x - button_size.width, button_offset.y - button_size.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.
class MyIphoneController < MyApplicationController def width 320 end def height 480 end def margin_bottom 20 end def margin_right 10 end end class MyIpadController < MyApplicationController def width 768 end def height 1024 end def margin_bottom 60 end def margin_right 20 end end
And in our AppDelegate, we will check for the device, and use the correct class.
@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.margin_left - size.width, self.width - self.margin_height - 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":