-
Notifications
You must be signed in to change notification settings - Fork 66
Animations
These do not affect the alpha channel; to hide an image in preparation for fade_in
, either set view.alpha = 0
or run the animation immediately view.fade_out(0)
.
self.view.show # => self.hidden = false
self.view.hide # => self.hidden = true
jQuery-like animation methods. They accept a "completed" callback that is passed an optional 'completed' boolean. These methods delegate to UIView.animateWithDuration(delay:options:animations:completion:)
or UIView.animateWithDuration(delay:usingSpringWithDamping:initialSpringVelocity:options:animations:completion:)
if you are using the :damping
option.
# default timeout is 0.3
view.fade_out
# with a callback
view.fade_out do
view.removeFromSuperview
end
# and the completed argument
view.fade_out do |completed|
view.removeFromSuperview
end
# fade_out options
view.fade_out(duration: 0.5,
delay: 0,
options: UIViewAnimationOptionCurveLinear,
opacity: 0.5)
view.move_to([0, 100]) # move to position 0, 100
view.delta_to([10, 100]) # move over 10, down 100, from current position
view.rotate_to Math::PI # rotate view upside down
view.rotate 45.degrees # rotate *an additional* 45 degrees
view.rotate_to(duration: 0.5, angle: 45.degrees) # using options
view.slide :left # slides the entire view left, right, up, or down. The
# default amount is the width of the view being moved, but
# you can override
view.slide :left, 320
view.slide :left, size: 320
view.shake # shakes the view.
# options w/ default values:
view.shake offset: 8, # move 8 px left, and 8 px right
repeat: 3, # three times
duration: 0.3, # for a total of 0.3 seconds
keypath: 'transform.translate.x'
# vigorous nodding - modifying transform.translation.y:
view.shake offset: 20, repeat: 10, duration: 5, keypath: 'transform.translation.y'
# an adorable wiggle - modifying transform.rotation:
view.shake offset: 0.1, repeat: 2, duration: 0.5, keypath: 'transform.rotation'
# this was pulled off warrenm's AHAlertView project. I thought the effect was
# awesome, and deserved more attention!
# https://github.com/warrenm/AHAlertView
view.tumble # the view will fall and rotate - a good 'cancel button effect'
# the opposite transition is also available
view.tumble_in
# and this "SuperGoodDeleteWiggle" is an aptly named animation care
# of mxcl (of PromiseKit, YOLOKit, and if he used RubyMotion I'm 99%
# sure he would be using SugarCube - see his "initWith...F**It' repo
# if you don't believe me)
# https://github.com/mxcl/SuperGoodDeleteWiggle
view.wiggle # weee! excellent 'delete/move' animation
view.super_good_delete_wiggle # aliased, with a hat tip to the creator
view.dont_wiggle
# since these are ongoing animations, they do *not* accept a "completion" block
The default behavior on all the animation methods is to animate from "the
current" position (UIViewAnimationOptionBeginFromCurrentState
). To disable
that, you can either assign options:
to something else, or you can disable
just that option. If your animation doesn't seem to have the correct initial
state, you might try this.
# in some cases, like if we're in the middle of an animation, setting the frame
# here doesn't have an "immediate" effect
view.frame = [[0, 0], [[100, 20]]
view.slide :left, from_current: false # frame will start from [0, 0] and slide out of the screen
Other options can be assigned this way, like the curve
view.slide :left, from_current: false, curve: :ease_in # :ease_in_out, :ease_in, :ease_out, :linear
Allow user interaction (by default it's disabled)
view.slide :left, allow_interaction: true
Not all options are configurable this way. Refer to UIViewAnimationOptions
and
assign them directly to options:
if there are options you need that are not
listed here.
view.slide :left, options: UIViewAnimationOptionAllowAnimatedContent | UIViewAnimationOptionCurveEaseInOut
Using the completion:
callback you can string animations together to create an
animation sequence.
view.slide(:left, 20) do
view.slide(:up, 20) do
view.slide(:right, 20) do
view.slide(:down, 20) do
view.fade_out
end
end
end
end
Those be some gnarly callbacks. In SugarCube you can write this as a chain instead!
UIView.animation_chain do
view.slide(:left, 20)
end.and_then do
view.slide(:up, 20)
end.and_then do
view.slide(:right, 20)
end.and_then do
view.slide(:down, 20)
end.and_then do
view.fade_out
end.start # <= make sure to call `start`!
Behind the scenes, calls to SugarCube animation methods (slide
, fade
,
rotate
) will not be run inside of a UIView#animateWithDuration(...)
block. Because of this, animation chains seem to be a little fickle. For
instance, you can call multiple animation methods inside the block, but
if you animate the same property twice, only the last animation will have
any effect.
UIView.animation_chain do
view.slide(:left, 20)
view.rotate(90.degrees)
end.and_then do
view.slide(:up, 20)
view.rotate(90.degrees)
end.and_then do
view.slide(:right, 20)
view.rotate(90.degrees)
end.and_then do
view.slide(:down, 20)
view.rotate(90.degrees)
end.and_then do
# here's an example of doing things *wrong*
view.fade_out # no effect
view.fade(0.5) # this animation "wins"
view.rotate_to(0.degrees)
end.start
Chains can also be written like this (why? so that you can add animations based on some application logic - the usual style is not as amenable to adding blocks conditionally).
chain = UIView.animation_chain
chain << proc { view.slide(:left, 20) }
chain << proc { view.slide(:up, 20) }
chain << proc { view.slide(:right, 20) }
chain << proc { view.slide(:down, 20) }
chain << proc { view.fade_out }
chain.start
AND chains can be looped! You can set a number of times, or call stop
on the
chain.
chain = UIView.animation_chain do
view.slide(:left, 20)
end.and_then do
view.slide(:right, 20)
end
chain.loop # loop forever
2.seconds.later { chain.stop } # the animation will complete, but not loop again
chain.loop(10) # would loop 10 times
# if you're impatient
chain.abort
# will stop the animation at the end of whatever block it is in, so it could be
# in a strange position, depending on where in the chain it is.
All the animations we've discussed so far are "UIKit animations". Core Animation offers a much richer framework to perform animations, and SugarCube has just a few helpers here (more to come!).
# A simple fade-in animation. If you haven't used CoreAnimation before, this might
# look a little unintuitive:
view.layer.opacity = 1
view.layer.basic_animation('opacity', from: 0)
# fade in, back out, and then in all the way
view.layer.keyframe_animation('opacity', values: [0, 0.5, 0.1, 1])
# similar effect using a cubic bezier path
path = UIBezierPath.bezierPath
path.moveToPoint([0, 0])
path.addCurveToPoint([1, 0], controlPoint1: [1.5, 0], controlPoint2: [-0.5, 0])
view.layer.keyframe_animation('opacity', path: path)