ASOC: Animating View Change

Hey Macscripters,
So I’m going to be changing views often, and I want to add an animation to it to make it a little nicer with the users. All of the views are going to be the same size, so I’m not changing the window size at all. I want to have a sliding effect, so the old view will slide out to the left with the new one sliding in from the right (kind of like when moving pages while in the Mac OS Installer, or when switching songs on an ipod). I would assume that these would be part of Core Animation, but I can’t figure out how to generate the effect for the life of me. Any help would be greatly appreciated. Thanks,

~Josh

Josh,

Have a look at the CATransitions docs. There are 2 properties, type and subtype, that you can set. One of the types is kCATransitionMoveIn and one of the subtypes is kCATransitionFromRight – sounds like just what you need.

Ric

Hi,

if the views are attached to a NSWindow, it’s quite easy with NSAnimatonContext and the animator of the window

mainWindow is the NSWindow instance of the window the views are attached to
previousView is the NSView instance of the current view
newView is the NSView instance of the new view
newFrame is an NSRect structure containing the frame parameter of the new view


set animationContext to current application's NSAnimationContext
animationContext's beginGrouping()
animationContext's currentContext's setDuration_(0.2)
mainWindow's contentView()'s animator()'s replaceSubview_with_(previousView, newView)
mainWindow's animator()'s setFrame_display_(newFrame, true)
animationContext's endGrouping()

Thank you so much for the quick replies guys!

Rdelmar,
I looked into CATransitions, and they look pretty promising. However, despite my fervent fidgeting with the code, I can get it to work. Here’s what I have:

set tr to current application's CATransition's animation()
tell tr
	setDuration_(0.25)
	setType_(current application's kCATransitionPush)
	setSubtype_(current application's kCATransitionFromRight)
	setTimingFunction_(current application's CAMediaTimingFunction's functionWithName_("kCAMediaTimingFunctionEaseInEaseOut")) --Always errors out here. Tells me that there's no such function as "kCAMediaTimingFunctionEaseInEaseOut" even though I've looked through the quartz core framework's header files and found that it is in fact there
end tell
mainWindow's contenView()'s addSubview_(newView)
previousView's removeFromSuperview()
mainWindow's addAnimation_forKey_(tr, missing value)

Stefan,
I tried your code, but it only animates the resizing and moving of the window, of which there will be none because each view will be the same size. I’m looking for a way to animate the change of views to make it look like one is pushing the other out, exactly like the kCATransitionFromRight function.

Thanks again both of you, this is very helpful!

~Josh

This worked for me:

script AppDelegate
	property parent : class "NSObject"
	property transition : missing value
	property firstView : missing value -- IBOutlet for an NSBox that covers the whole content view
	property secondView : missing value -- IBOutlet for a new NSBox to replace firstView
	property parentView : missing value -- IBOutlet for the contentView of the window
	
	on applicationWillFinishLaunching_(aNotification)
		set transition to current application's CATransition's animation()
		transition's setType_(current application's kCATransitionPush)
		transition's setSubtype_(current application's kCATransitionFromRight)
        transition's setDuration_(.5)
        set dict to current application's NSDictionary's dictionaryWithObject_forKey_(transition,"subviews")
		parentView's setAnimations_(dict)
	end applicationWillFinishLaunching_
	
	on buttonClick_(sender)
		parentView's animator()'s replaceSubview_with_(firstView, secondView)
	end buttonClick_
	end script

I just made an NSBox (of the custom type, so I could give it a background color) that was the same size as the window’s contentView – this was added to the content view in IB. I made a second box (not in the window, just off to the side) that was connected to secondView.

Ahhh ok, you’re using NSBox’s and keeping a parent NSView. I was using different NSViews and keeping a parent NSWindow. Ok, that makes sense. When I plug in your code however, everything seems to go great, the NSBoxes switch, but there’s no animation to it. I tried to animate it the same way with UIView, but the same thing is happening. Could this be an error with my Xcode? And if so, could you send me your project file? This is the code I used for the UIView:

tell current application's UIView
	beginAnimations_context_(missing value, missing value)
	setAnimationDuration_(0.25)
	setAnimationTransition_forView_cache_(current application's UIViewAnimationTransitionFlipFromLeft(), parentView, true)
end tell
if sender's |tag|() as number = 1 then
	firstBox's removeFromSuperview()
	parentView's addSubview_(secondBox)
else
	secondBox's removeFromSuperview()
	parentView's addSubview_(firstBox)
end if
current application's UIView's commitAnimations()

consider, that iOS doesn’t support AppleScriptObjC and NSView is not exchangeable with UIView

Ahh, I was not aware of that. It was my understanding that UIView and NSView were perfectly interchangeable. Ok, sorry about that. But that still leaves the unresolved issue of the CATransition not working for me. Do you know why that would be?

Did you add a layer to your contentView in IB?

I’m using NSBoxes like you said, so I have one NSBox in the window, and then I made a new custom view (NSView) to house the other NSBox and then connected everything in IB, copying your code exactly. Could you maybe zip and upload your project folder to a file sharing site like DropBox or MegaUpload so that I can take a look and compare yours with mine to see what I’m doing?

If you PM me, I can just email you a copy, it’s not very big. But you didn’t answer my question about adding the layer – by that, I mean did you go into the View Effects Inspector in IB and select the check box for the core animation layer for the contentView of your window. This animation won’t work if that’s not checked.

Ric

Ahhh ok. So sorry about that. I’ve seen that so many times before it just skipped my mind that I’d actually need it. Ok, so I checked core animation for the NSView, and NSBoxes, but now when I attempt to run it (with all of your code again), I get this error:

[NSAppleEventDescriptor _fastCStringContents:]: unrecognized selector sent to instance 0x200742440

And afterwards the app becomes unresponsive.