Showing posts with label Core Animation. Show all posts
Showing posts with label Core Animation. Show all posts

Wednesday, April 7, 2010

iCal-like popup window Part II - MAAttachedWindow and CoreAnimation

Looking closely at the iCal dialog it behaves quite differently from my first cut - what it does is to scale an image of the dialog from a single starting point to something slightly bigger than the final size and then back down to final size. There is a movie of this on my previous post. This gives an appearance like it over-scales and snaps back. To me this is really good because that sort of "pop" makes it very noticeable. This happens with the strange (but good) yellow "found text" marker that appears in many Apple apps including Safari, and XCode.
So how to do this type of effect? The basic story seems to be that you need to:
  • Get an image of the complete window (as it will be drawn)
  • Scale it from the initial start point to the final size (via an oversize) using CoreAnimation.
The animation needs to be hosted in window - if you created a window with no frame (NSBorderlessWindowMask) this would seem to be a good place to host it. Then the animation can be performed either by resizing the view or by trickery on the underlying CALayer. Both would work.

There are as ever many ways to skin the cat. The simplest solution is actually a category of NSWindow that has been opensourced by NoodleSoft great blog can be found here and code is hosted on github.

What Paul Kim (think of him as Mr Noodle) has done is rather clever and wonderfully simple - the recipe is this:
  • Get an image of your window as it will be
  • Create a new transparent window (NSBorderlessWindowMask)
  • Set the content view of the window to be an NSImage - with the image that you want to see (the image of your window)
  • Call setFrame:display:animate: with a start and end rectangle
  • When the animation is complete destroy your window and show your finished window.

I have tickled his code a little to get the overshoot and pull-back for that "pop" effect - just call setFrame:display:animate: twice once for too big and once for the right size. But it is a tiny tickle. Also, and importantly, as the animation is done in an entirely separate window it will work with Mat Gemmel's MAAttachedWindow.

I attache a movie of this done with a demo version of IShowU

Wednesday, March 31, 2010

iCal-like popup window Part I - MAAttachedWindow and CoreAnimation

I have been working on animating the insert frames window in the same way that the iCal window animates. The iCal window does not just appear but instead sort of grows out of the point that you double clicked in.
It is a really nice effect - however rather than the 10 minuets (or so) I thought it would take to deploy it - in actual fact it has taken me a little while to get to the bottom of it.

My first port of call was Core Animation. I have not done any Core Animation before so it was my first look at it. Core Animation is beautiful - doing simple animations is pretty straight forward. An animation like changing a window's bounds or moving it's location is quite simple. However it is not possible to do this kind of animation with Mat Gemmel's MAAttachedWindow.

MAAttachedWindow is quite interesting and clever - what it does is create a pattern that is the window image (a bitmap) and then sets this pattern as the window background colour. So when the window draws it's background in it's background colour this magically draws the window. There is also some code that will keep the window geometry in sync with it's contents this makes it impossible to grow or shrink the window.

I had a solution to this which was to use Core Animation to resize the contents of the window and from this then recalculate the geometry of the window its self. This sort of worked - things animated but in a nasty lumpy fashion. Grubbing around on the web I found this reference to the problem.
The arrow is harder. There's a window with an arrow on Matt Gemmell's site http://mattgemmell.com/ but that uses an NSColor with a pattern image to fill the window background and that seems mess up with core animation, which can't cache the drawn window prior to animation.
There are other ways to draw custom windows. Apple have some excellent Sample code RoundTransparentWindow that draws a custom window. Their method is a little more straight forward than MAAttachedWindow - the window is 100% transparent and within the window is a view that draws the window background. Taking this approach and rolling my selves up for some fun and games with drawing paths gave me a window that animated smoothly.


As you can see - animates nice and smoothly - but is very different than what happens in iCal.