Hey guys,
So I’ve been running into a bit of trouble lately with Objective-C. There’s this great class called CATransition that switches the views with a nice animated slide (either up, down, right, or left). However, for whatever reason, you cannot use the kCATransitionPush transition with any of the transition subtypes in Snow Leopard, only in Lion and now Mountain Lion (this may or may not be true for the other transition types as well, I haven’t tested them yet). Because of this, coupled with the fact that most of what I’m making is geared toward my Snow Leopard machine, I made a class that uses CABasicAnimation to act like CATransition’s kCATransitionPush and decided to post it here for anyone else with the same problem. I also added a bit of Shane Stanley’s code to make it so that if the views are different sizes, the window itself will change size to fit the new NSView. It’s pretty self explanatory, oldView is the current view, newView is the new view, theWindow is the NSWindow housing the NSView’s, parentView is the NSWindow’s NSView that contains the subviews, resizeWin is whether or not the animation should resize the window (true to resize, false to just animate the changing of views), and theDirection is either “left,” “right,” “up,” or “down.” If you want to give it a try, here’s a project folder download (http://dl.dropbox.com/u/36103137/Example.zip) with all of the IB connections and code ready to run. If you have any comments or comments, please post them. Enjoy!
~Josh
-- MyTransitions.applescript
-- Example
-- Created by Josh Fletcher on 7/30/12.
-- Copyright 2012 ChumpApps All rights reserved.
script MyTransitions
property parent : class "NSObject"
property oView : ""
on changeView______(oldView, newView, theDirection, theWindow, resizeWin, parentView)
set theDirection to theDirection as string
set oView to oldView
set oldFrame to oldView's frame()
set newFrame to newView's frame()
parentView's addSubview_(newView)
if theDirection = "Up" then newView's setFrameOrigin_({(x of origin of oldFrame), (height of |size| of oldFrame)})
if theDirection = "Down" then newView's setFrameOrigin_({(x of origin of oldFrame), -1 * (height of |size| of newFrame)})
if theDirection = "Right" then newView's setFrameOrigin_({(width of |size| of oldFrame), (y of origin of oldFrame)})
if theDirection = "Left" then newView's setFrameOrigin_({-1 * (width of |size| of newFrame), (y of origin of oldFrame)})
set newFrame to newView's frame()
set firstAnimation to current application's CABasicAnimation's animationWithKeyPath_("position")
tell firstAnimation
setDelegate_(me)
setRemovedOnCompletion_(false)
setFromValue_(current application's NSValue's valueWithPoint_(origin of oldFrame))
setToValue_(current application's NSValue's valueWithPoint_({(x of origin of oldFrame) - (x of origin of newFrame), (y of origin of oldFrame) - (y of origin of newFrame)}))
setDuration_(1.5)
setTimingFunction_(current application's CAMediaTimingFunction's functionWithControlPoints____(0.25, 0.1, 0.25, 1)) -- for smooth transition use (0.1, 2.5, 0.3, 0.3)
end tell
set secondAnimation to current application's CABasicAnimation's animationWithKeyPath_("position")
tell secondAnimation
setRemovedOnCompletion_(false)
setFromValue_(current application's NSValue's valueWithPoint_(origin of newFrame))
setToValue_(current application's NSValue's valueWithPoint_({(x of origin of oldFrame), (y of origin of oldFrame)}))
setDuration_(1.5)
setTimingFunction_(current application's CAMediaTimingFunction's functionWithControlPoints____(0.25, 0.1, 0.25, 1)) -- for smooth transition use (0.1, 2.5, 0.3, 0.3)
end tell
newView's layer()'s addAnimation_forKey_(secondAnimation, "position")
oldView's layer()'s addAnimation_forKey_(firstAnimation, "position")
if resizeWin then
set theFrame to newView's frame()
set height of |size| of theFrame to (height of |size| of theFrame)
tell theWindow
set theFrame to frameRectForContentRect_(theFrame)
set {origin:{x:frameX, y:frameY}, |size|:{width:frameWidth, height:frameHeight}} to theFrame
set {origin:{x:windowX, y:windowY}, |size|:{width:windowWidth, height:windowHeight}} to frame()
set newOrigin to {x:windowX - (frameWidth - windowWidth) / 2, y:windowY - frameHeight + windowHeight}
set newFrame to {origin:newOrigin, |size|:{width:frameWidth, height:frameHeight}}
set newFrame to my adjustFrame_forScreenOfWindow_(newFrame, theWindow)
setFrame_display_animate_(newFrame, true, true)
end tell
end if
tell oldView to setFrameOrigin_({(x of origin of oldFrame) - (x of origin of newFrame), (y of origin of oldFrame) - (y of origin of newFrame)})
tell newView to setFrameOrigin_({(x of origin of oldFrame), (y of origin of oldFrame)})
end changeView______
on adjustFrame_forScreenOfWindow_(proposedFrame, aWindow)
set {origin:{x:windowX, y:windowY}, |size|:{width:windowWidth, height:windowHeight}} to proposedFrame
set screenFrame to aWindow's screen()'s visibleFrame()
set {origin:{x:frameX, y:frameY}, |size|:{width:frameWidth, height:frameHeight}} to screenFrame
if windowX < frameX then set windowX to frameX
if windowX + windowWidth > frameX + frameWidth then set windowX to frameX + frameWidth - windowWidth
if windowY < frameY then set windowY to frameY
return {origin:{x:windowX, y:windowY}, |size|:{width:windowWidth, height:windowHeight}}
end adjustFrame_forScreenOfWindow_
on animationDidStop_finished_(theAnimation, flag)
tell oView to removeFromSuperview()
end animationDidStop_finished_
end script