Swapping NSViews using a push transition - objective-c

I've been trying to figure this out for a while but I can't seem to get it. How would I swap two NSViews using a push transition (like what UINavigationController does on iOS)? What I've tried so far:
Using an NSAnimation subclass <-- too slow
Using NSViewAnimation and MGViewAnimation <-- too slow
Using the NSView animator proxy <-- too slow
Using CATransition <-- I can't use this because CATransition requires the views to be layer backed, and layer backing views causes text rendering glitches as well as various other graphical artifacts

The first 3 options are probably too slow because you're trying to use them without layer-backing your views. To do animation in AppKit, you're going to need to have your views backed by layers.

It seems that the animation is slow because I'm animating a pretty large view. I don't think there's any way around that other than the good old image swap trick (taking an image of the view and animating that instead of the view itself).

Related

Using Core Animation for a custom CATranstion

I would like to implement a new CATransition.
For example, let's say I would like to do this effect: a n by m array of two sided layers that have a portion of the source image on one side, and the a portion of the destination image on the other side. Each layer would rotate around its x axis by 180 degrees to reveal the other side. Can such a logic (animated CALayers) be used for a CATransition ?
I don't think you can do this. The only way to customize CATransition beyond the built-in types and subtypes, is by using a CIFilter(from iOS 5.0 or OSX 10.5). And the only way to create a custom CIFilter beyond chaining and configuring built-in filters is, according to the doc :
You can subclass CIFilter in order to create:
A filter by chaining together two or more built-in Core Image filters (iOS and OS X)
A custom filter that uses an image processing kernel that you write (OS X only)
So doing this based on CALayer animations is not possible.
On OSX this should be managable with some math work, but not directly using CALayers animations. In iOS this is simply not possible.
Instead of doing a CATransition you could achieve the same effect by using layers directly, but obviously it would not integrate as easily in your UI code.
I have written a transition effect like you describe, but it was not a CATransition. Instead, I created my own method to handle view transitions, and invoke that.
My transition cut the two views into vertical slices, and then did an animation where I start rotating the slices around their Y axes, starting with the left-most slice and working to the right, which creates a cool-looking cascade effect. It took quite a bit of work with CAAnimationGroup obbjects, plus using beginTime for each strip's animation to stagger it's beginning. That one transition animation took about 5 pages of code.

Implement Fan View - Cocoa

I am trying to implement a Fan view like the ones in the Mac OS X dock, such as the Downloads and Documents folders, using Cocoa.
I am currently adding a button on a transparent window's content view and animating the button's frame using NSViewAnimation (group animation). But the animation is not as smooth as expected.
Is there any other optimized way for implementing this?
You should be using Core Animation for this. You should create a transparent view/window that's large enough to contain your whole animation. You should then use CALayer objects to perform the actual animation.
Core Animation layers are essentially high-level lightweight wrappers around OpenGL surfaces and the rendering of the layers is done by the GPU, giving much better performance than CPU-managed animation such as NSViewAnimation.
Bear in mind that because Core Animation layers are lightweight, they don't have any event-handling built into them, so you'll need to do all the mouse tracking in your view/view controller.
Your other option is using layer-backed views (which have their own CALayer) and animating the buttons' positions using the animator proxy. This may be enough to achieve what you want, and because the buttons are still full NSButton objects they still have all the NSView event handling.
You should probably read the Animation Overview to give you a better idea of how all these technologies work.

How to manage memory in scolling components?

Are there known and proven ways to manage memory with scrolling components like tables or grids other than recycling cells as is used in Cocoa? The sequence of calculations and datasource/delegation calls needed to make this way of laying out views works but also makes coordinating complex animations with the cells and a scroll view error prone as you have to pay careful attention to the sequence of calls as it reloads data, scrolls to an offset and other mechanisms of the layout that affect the target frame of your animations. I am looking for a more declarative approach to providing content to the scroll view and having it figure out a smart way to manage it's memory as is done by a browser when you load the DOM with a long vertical layout of pictures.
I found it easier to create my own custom layout classes that only do layout on my views and not to impose an elaborate protocol such as NSTableViewDataSource and the like that makes animation difficult to program. I like to know exactly where my views are at all times, the complete hierarchy of each view and I don't like to keep a model in sync with my views so I store data on the views themselves. In my mind the objects on screen are the one and only objects I like to orchestrate as a programmer. I want direct declarative control over them kind of like a game programer. By subclassing a scroll view directly and following very simple layout rules outside of the normal layoutSubviews methods of Cocoa to avoid surprise layouts, I was able to control my animations better and do more complex and fluid animations. Hope this inspires someone to do the same.

maskToBounds:YES affecting scroll performance

I have several UIButtons on a UIScrollView. I want the buttons to have rounded corners, so I call maskToBounds: on each of them. When I do this and run on the device, the scrolling framerate is pretty bad (it works fine on the simulator). Any ideas on a workaround for this problem?
You're causing the view to be composited offscreen with that call to masksToBounds:, which slows things down quite a bit. Are you rendering custom button images? If so use UIImage -stretchableImageWithLeftCapWidth:topCapHeight: with an image which is the minimum width to encompass it's rounded edges. This allows the GPU to handle stretching the image in the most efficient way possible, while still giving you a button made out of an image. There is a session in the WWDC 2011 videos on Drawing in UIKit - watch that, as it addresses exactly this problem, and a few others you're likely to have.
A few alternative methods:
Tweeties implementation of fast scrolling, by drawing everything manually
Matt Gallaghers implementation of custom drawing. This is the method I use, as it's easy to maintain

Keeping backing CAGradientLayer static when UITableView scrolls

I'm trying to use a CAGradientLayer as a background for a UITableView. Everything works well until the overlaying view is scrolled, at which point then the pre-rendered background scrolls up and out of the way along with the original screen of data.
This is code that is being migrated from an iOS 3.1.3 app using a UIImage as a background to something device/resolution independent-looks great, works well, but sniffing the device type and using an alternate png isn't the sort of code that I want to ship, much less maintain.
Any suggestions as to how to do this?
Found the solution to what I was trying to solve, courtesy of Matt Gallagher:
http://cocoawithlove.com/2009/08/adding-shadow-effects-to-uitableview.html
His blog post has quite a few nice touches, including shadowing relevant cells instead of the whole table (mentioned as a performance issue in Noah's response).
You may have to make the table view transparent, and add the gradient layer to the table's superview. Keep in mind that your scrolling performance is probably going to be hideous—Core Animation will have to composite every subview of the table for every frame it displays. You may be able to slightly mitigate this by setting the cells' layers to rasterize themselves, as described here, but expect things to be pretty choppy regardless.