Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Port of MoveMe app from iOS sample code #19

Merged
merged 4 commits into from

2 participants

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jun 19, 2012
  1. @srfarley
Commits on Jun 20, 2012
  1. @srfarley

    added README

    srfarley authored
  2. @srfarley
Commits on Jun 23, 2012
  1. @srfarley

    coverted tabs to spaces

    srfarley authored
This page is out of date. Refresh to see the latest.
View
5 MoveMeRuby/.gitignore
@@ -0,0 +1,5 @@
+.repl_history
+build
+resources/*.nib
+resources/*.momd
+resources/*.storyboardc
View
16 MoveMeRuby/README
@@ -0,0 +1,16 @@
+MoveMeRuby.app
+
+This sample app demonstrates simple drawing, touch handling, and animation using UIKit and Core
+Animation.
+
+When you touch inside the placard, it pulses and centers under the touch point. You can then move it
+around the screen and it stays centered on the touch. When you remove your finger, the placard moves
+back to the center of the screen and bounces.
+
+Double-tapping outside of the placard displays the welcome message in a different language. The list
+of messages is stored in the UTF16-encoded file 'resources/DisplayStrings.txt'.
+
+This is a Ruby port of the original Objective-C project from the iOS sample code:
+http://developer.apple.com/library/ios/#samplecode/moveme/Introduction/Intro.html
+
+The initial port was done by Steven R. Farley <srfarley@gmail.com>.
View
8 MoveMeRuby/Rakefile
@@ -0,0 +1,8 @@
+$:.unshift("/Library/RubyMotion/lib")
+require 'motion/project'
+
+Motion::Project::App.setup do |app|
+ # Use `rake config' to see complete project settings.
+ app.name = 'MoveMeRuby'
+ app.frameworks += %w(CoreAnimation)
+end
View
10 MoveMeRuby/app/app_delegate.rb
@@ -0,0 +1,10 @@
+class AppDelegate
+
+ def application(application, didFinishLaunchingWithOptions: launchOptions)
+ @window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
+ @window.rootViewController = MoveMeViewController.alloc.init
+ @window.makeKeyAndVisible
+ true
+ end
+
+end
View
146 MoveMeRuby/app/move_me_view.rb
@@ -0,0 +1,146 @@
+class MoveMeView < UIView
+
+ def initWithFrame(frame)
+ if super
+ # Create the placard view -- its init method calculates its frame based on its image
+ @placard_view = PlacardView.alloc.init
+ @placard_view.center = self.center
+ self.addSubview(@placard_view)
+ end
+ self
+ end
+
+ def placardView
+ @placard_view
+ end
+
+ def touchesBegan(touches, withEvent: event)
+ # We only support single touches, so anyObject retrieves just that touch from touches
+ touch = touches.anyObject
+
+ # Only move the placard view if the touch was in the placard view
+ if touch.view == placardView
+ # Animate the first touch
+ animateFirstTouchAtPoint(touch.locationInView(self))
+ else
+ # In case of a double tap outside the placard view, update the placard's display string
+ placardView.setupNextDisplayString if touch.tapCount == 2
+ end
+ end
+
+ def touchesMoved(touches, withEvent: event)
+ touch = touches.anyObject
+
+ # If the touch was in the placardView, move the placardView to its location
+ if touch.view == placardView
+ location = touch.locationInView(self)
+ placardView.center = location
+ end
+ end
+
+ def touchesEnded(touches, withEvent: event)
+ touch = touches.anyObject
+
+ # If the touch was in the placardView, bounce it back to the center
+ if touch.view == placardView
+ # Disable user interaction so subsequent touches don't interfere with animation
+ self.userInteractionEnabled = false
+ animatePlacardViewToCenter
+ end
+ end
+
+ def animationDidStop(theAnimation, finished: flag)
+ # Animation delegate method called when the animation's finished:
+ # restore the transform and reenable user interaction
+ placardView.transform = CGAffineTransformIdentity
+ self.userInteractionEnabled = true
+ end
+
+ private
+
+ GROW_ANIMATION_DURATION_SECONDS = 0.15
+ MOVE_ANIMATION_DURATION_SECONDS = 0.15
+
+ def animateFirstTouchAtPoint(touch_point)
+ # "Pulse" the placard view by scaling up then down, then move the placard to under the finger.
+ UIView.animateWithDuration(GROW_ANIMATION_DURATION_SECONDS,
+ animations: -> {
+ placardView.transform = CGAffineTransformMakeScale(1.2, 1.2)
+ },
+ completion: -> (finished) {
+ UIView.animateWithDuration(MOVE_ANIMATION_DURATION_SECONDS,
+ animations: -> {
+ placardView.transform = CGAffineTransformMakeScale(1.1, 1.1)
+ placardView.center = touch_point
+ }
+ )
+ }
+ )
+ end
+
+ def animatePlacardViewToCenter
+ # Bounces the placard back to the center
+
+ welcomeLayer = placardView.layer
+
+ # Create a keyframe animation to follow a path back to the center
+ bounceAnimation = CAKeyframeAnimation.animationWithKeyPath(:position)
+ bounceAnimation.removedOnCompletion = false
+
+ animationDuration = 1.5
+
+ # Create the path for the bounces
+ thePath = CGPathCreateMutable()
+
+ midX = self.center.x
+ midY = self.center.y
+ originalOffsetX = placardView.center.x - midX
+ originalOffsetY = placardView.center.y - midY
+ offsetDivider = 4.0
+
+ stopBouncing = false
+
+ # Start the path at the placard's current location
+ CGPathMoveToPoint(thePath, nil, placardView.center.x, placardView.center.y)
+ CGPathAddLineToPoint(thePath, nil, midX, midY)
+
+ # Add to the bounce path in decreasing excursions from the center
+ while !stopBouncing
+ CGPathAddLineToPoint(thePath, nil, midX + originalOffsetX / offsetDivider,
+ midY + originalOffsetY / offsetDivider)
+ CGPathAddLineToPoint(thePath, nil, midX, midY)
+
+ offsetDivider += 4
+ animationDuration += 1 / offsetDivider
+ if ((originalOffsetX / offsetDivider).abs < 6) && ((originalOffsetY / offsetDivider).abs < 6)
+ stopBouncing = true
+ end
+ end
+
+ bounceAnimation.path = thePath
+ bounceAnimation.duration = animationDuration
+
+ # Create a basic animation to restore the size of the placard
+ transformAnimation = CABasicAnimation.animationWithKeyPath(:transform)
+ transformAnimation.removedOnCompletion = true
+ transformAnimation.duration = animationDuration
+ transformAnimation.toValue = NSValue.valueWithCATransform3D(CATransform3DIdentity)
+
+ # Create an animation group to combine the keyframe and basic animations
+ theGroup = CAAnimationGroup.animation
+
+ # Set self as the delegate to allow for a callback to reenable user interaction
+ theGroup.delegate = self
+ theGroup.duration = animationDuration
+ theGroup.timingFunction = CAMediaTimingFunction.functionWithName(KCAMediaTimingFunctionEaseIn)
+ theGroup.animations = [bounceAnimation, transformAnimation]
+
+ # Add the animation group to the layer
+ welcomeLayer.addAnimation(theGroup, forKey: :animatePlacardViewToCenter)
+
+ # Set the placard view's center and transformation to the original values in preparation for the
+ # end of the animation
+ placardView.center = self.center
+ placardView.transform = CGAffineTransformIdentity
+ end
+end
View
8 MoveMeRuby/app/move_me_view_controller.rb
@@ -0,0 +1,8 @@
+class MoveMeViewController < UIViewController
+
+ def loadView
+ super
+ self.view = MoveMeView.alloc.initWithFrame(UIScreen.mainScreen.bounds)
+ end
+
+end
View
82 MoveMeRuby/app/placard_view.rb
@@ -0,0 +1,82 @@
+class PlacardView < UIView
+
+ def init
+ # Retrieve the image for the view and determine its size
+ image = UIImage.imageNamed('Placard.png')
+ frame = CGRectMake(0, 0, image.size.width, image.size.height)
+
+ # Set self's frame to encompass the image
+ if initWithFrame(frame)
+ self.opaque = false
+ @placard_image = image
+
+ # Load the display strings
+ path = NSBundle.mainBundle.pathForResource('DisplayStrings', ofType: 'txt')
+ string = NSString.stringWithContentsOfFile(path,
+ encoding: NSUTF16StringEncoding, # originally NSUTF16BigEndianStringEncoding, which fails
+ error: nil)
+ @displayStrings = string.split("\n")
+ @displayStringsIndex = 0
+ setupNextDisplayString
+ end
+ self
+ end
+
+ def drawRect(rect)
+ # Draw the placard at 0, 0
+ @placard_image.drawAtPoint(CGPointMake(0, 0))
+
+ # Draw the current display string.
+ # Typically you would use a UILabel, but this example serves to illustrate the UIKit extensions
+ # to NSString. The text is drawn center of the view twice - first slightly offset in black,
+ # then in white -- to give an embossed appearance.
+ # The size of the font and text are calculated in setupNextDisplayString.
+
+ # Find point at which to draw the string so it will be in the center of the view
+ x = bounds.size.width / 2 - @textSize.width / 2
+ y = bounds.size.height / 2 - @textSize.height / 2
+
+ # Get the font of the appropriate size
+ font = UIFont.systemFontOfSize(@fontSize)
+
+ UIColor.blackColor.set
+ point = CGPointMake(x, y + 0.5)
+ @currentDisplayString.drawAtPoint(point,
+ forWidth: bounds.size.width - STRING_INDENT,
+ withFont: font,
+ fontSize: @fontSize,
+ lineBreakMode: UILineBreakModeMiddleTruncation,
+ baselineAdjustment: UIBaselineAdjustmentAlignBaselines)
+
+ UIColor.whiteColor.set
+ point = CGPointMake(x, y)
+ @currentDisplayString.drawAtPoint(point,
+ forWidth: bounds.size.width - STRING_INDENT,
+ withFont: font,
+ fontSize: @fontSize,
+ lineBreakMode: UILineBreakModeMiddleTruncation,
+ baselineAdjustment: UIBaselineAdjustmentAlignBaselines)
+ end
+
+ def setupNextDisplayString
+ # Get the string at the current index, then increment the index
+ @currentDisplayString = @displayStrings[@displayStringsIndex]
+ @displayStringsIndex += 1
+ @displayStringsIndex = 0 if @displayStringsIndex >= @displayStrings.length
+
+ # Precalculate size of text and size of font so that text fits inside placard
+ fontSizePtr = Pointer.new(:float)
+ @textSize = @currentDisplayString.sizeWithFont(UIFont.systemFontOfSize(24),
+ minFontSize: 9.0,
+ actualFontSize: fontSizePtr,
+ forWidth: bounds.size.width - STRING_INDENT,
+ lineBreakMode: UILineBreakModeMiddleTruncation)
+ @fontSize = fontSizePtr[0]
+ setNeedsDisplay
+ end
+
+ private
+
+ STRING_INDENT = 20
+
+end
View
BIN  MoveMeRuby/resources/DisplayStrings.txt
Binary file not shown
View
BIN  MoveMeRuby/resources/Placard.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
9 MoveMeRuby/spec/main_spec.rb
@@ -0,0 +1,9 @@
+describe "Application 'MoveMeRuby'" do
+ before do
+ @app = UIApplication.sharedApplication
+ end
+
+ it "has one window" do
+ @app.windows.size.should == 1
+ end
+end
Something went wrong with that request. Please try again.