popViewControllerAnimated: custom transition animation? - xcode

Yes, I have looked for an answer already. None of the solutions work, except one that doesn't give the option for a fade transition, only flip or curl.
Like this:
methodname
configure animation
[self.navigationController popViewControllerAnimated:NO];
No matter what variety of transition animation config I try, nothing is visibly different from only using the typical single-line pop. If I change it to …Animated:YES];, I get the standard pop animation, maybe with something weird happening from the broken config.
So my question is this: How can I do a pop with, if not CrossDissolve, then at least something that looks the same? Is that even possible with a navigation controller?
Using modal views would have the default animation I want, and I could manage the view stack easily enough, but I don't want to do that.

For this type of transition I would really recommend a modal view controller, thats the way the system was designed.
But if you insist on using the navigation controller there is a way, though somewhat ugly.
[CATransaction begin];
[CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
CATransition *transition = [CATransition animation];
[transition setType:kCATransitionFade];
[self.navigationController.view.layer addAnimation:transition forKey:#"someAnimation"];
[self.navigationController popViewControllerAnimated:YES];
[CATransaction commit];
The CATransaction will disable all standard animations. The CATransition adds a fade transition to the navigation controller layer when views are swapped (in this case removing the viewcontroller view that is popped).

In iOS 7 above, you may want to look into UIViewControllerAnimatedTransitioning for presented view controllers, or UINavigationControllerDelegate method :
- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC
I have some sample code from another question for more info.

Joris Kluivers's answer in Swift 3 :
CATransaction.begin()
CATransaction.setDisableActions(true)
let animation = CATransition()
animation.type = kCATransitionFade
self.navigationController?.view.layer.add(animation, forKey: "someAnimation")
_ = self.navigationController?.popViewController(animated: false)
CATransaction.commit()

Related

Auto-layout and transforms not working together for UIViewController transition

I have a UIViewController being presented with a UIViewControllerAnimatedTransitioning object to do the animation. The animation has a collection view cell expand and fade out as the new view controller's view fades in, expanding in the same way. So it looks like you have an expanding cell that transforms into the new view controller. But weirdly enough, the subviews of the cell get transformed in weird ways when they use auto-layout. When I don't use auto-layout, this doesn't happen. What might be the issue?
Try adding your cell to [[transitionContext containerView] superview] in - (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext, instead of [transitionContext containerView]
For some reason this worked for me

Are layer-hosting NSViews allowed to have subviews?

Layer-hosting NSViews (so NSViews that you supply a CALayer instance for and set it with setLayer:) can obviously contain subviews. Why obviously? Because in Apple's own Cocoa Slides sample code project, you can check a checkbox that switches the AssetCollectionView from being layer-backed to being layer-hosting:
- (void)setUsesQuartzCompositionBackground:(BOOL)flag {
if (usesQuartzCompositionBackground != flag) {
usesQuartzCompositionBackground = flag;
/* We can display a Quartz Composition in a layer-backed view tree by
substituting our own QCCompositionLayer in place of the default automanaged
layer that AppKit would otherwise create for the view. Eventually, hosting of
QCViews in a layer-backed view subtree may be made more automatic, rendering
this unnecessary. To minimize visual glitches during the transition,
temporarily suspend window updates during the switch, and toggle layer-backed
view rendering temporarily off and back on again while we prepare and set the
layer.
*/
[[self window] disableScreenUpdatesUntilFlush];
[self setWantsLayer:NO];
if (usesQuartzCompositionBackground) {
QCCompositionLayer *qcLayer = [QCCompositionLayer compositionLayerWithFile:[[NSBundle mainBundle] pathForResource:#"Cells" ofType:#"qtz"]];
[self setLayer:qcLayer];
} else {
[self setLayer:nil]; // Discard the QCCompositionLayer we were using, and let AppKit automatically create self's backing layer instead.
}
[self setWantsLayer:YES];
}
}
In the same AssetCollectionView class, subviews are added for each image that should be displayed:
- (AssetCollectionViewNode *)insertNodeForAssetAtIndex:(NSUInteger)index {
Asset *asset = [[[self assetCollection] assets] objectAtIndex:index];
AssetCollectionViewNode *node = [[AssetCollectionViewNode alloc] init];
[node setAsset:asset];
[[self animator] addSubview:[node rootView]];
[nodes addObject:node];
return [node autorelease];
}
When I build and run the app and play around with it, everything seems to be fine.
However, in Apple's NSView Class Reference for the setWantsLayer: method it reads:
When using a layer-hosting view you should not rely on the view for
drawing, nor should you add subviews to the layer-hosting view.
What is true? Is the sample code incorrect and it's just a coincidence that it works? Or is the documentation false (which I doubt)? Or is it OK because the subviews are added through the animator proxy?
When AppKit is "layer hosting" we assume you may (or may not) have a whole subtree of layers that AppKit doesn't know about.
If you add a subview to the layer hosted view, then it might not come out in the right sibling order that you want. Plus, we sometimes add and remove them, so it might change depending on when you call setLayer:, setWantsLayer: or when the view is added or removed from the superview. On Lion (and before) we remove the layers that we "own" (ie: layer backed) when the view is removed from the window (or superview).
It is okay to add subviews...their children-sibling-order in the sublayers array just might not be deterministic if you have sibling-layers that aren't NSViews.
I don't know what's the "right" answer to this. But I do think that the CocoaSlides example works within the boundaries of what the docs say you "shouldn't" do. In the example, look at where the insertNodeForAssetAtIndex: method is called, and you'll see that it only happens when the view is being populated, before it ever is assigned a layer or has setWantsLayer: called on it.
The docs don't say that a layer-hosted view can't contain any subviews, they just say that you can't add and subviews to one. At the point in time when those subviews are added, the main view hasn't yet become a layer-hosting view. After it has been turned into a layer-hosting view by having a manually created layer assigned to it, no more subviews are added.
So there's really no contradiction between the docs and this particular example. That being said, it could be interesting to explore this further, maybe by switching on the QC background layer right from the start, e.g. by sticking a [self setUsesQuartzCompositionBackground:YES]; right inside initWithFrame:.
SPOLIER ALERT:
It seems to work just fine. The creation of the display is a bit slower (not surprising with all that QC animation going on), but apart from that it's smooth sailing.
One comment about this code from Apple: it's busted.
When you first start the app up, note the nice gradient background. Turn QC on, then off.
Poof, no more gradient background.

Oomph MacMapKit Drawing Wrong

I've integrated Oomph MacMapKit in one of my projects, I did all the steps. But there is a problem.
I'm using a NSToolbar and switching between the views. whenever I'm in my map page if I switch into another page and then switch back to the map page, the map is drew under the MKMapView and MKMapView is white but I can navigate in map by dragging mouse in the white area.
I've tried it in another project as well, And it acts just like this again.
Normal Look
After switching back
Does anyone know how can I fix this?
This code is running in my window controller delegate for switching pages
- (NSView*)viewForTag:(int)tag
{
switch (tag)
{
case 0:
return [firstViewController view];
break;
case 1:
return [secondViewController view];
break;
default:
return [firstViewController view];
break;
}
}
- (IBAction)switchViews:(id)sender
{
NSView* currentView = [self viewForTag:[sender tag]];
NSView* previousView = [self viewForTag:currentViewTag];
currentViewTag = [sender tag];
[[[[self window] contentView] animator] replaceSubview:previousView with:currentView];
}
There is no special code in maps page.
Thanks in advance
I cannot fault your code. I presume you stepped through your code and checked that all views are properly added and removed. Also, you might want to check what frame is set for your map view after the switch. If the NSRect for the frame is where your white space is, somehow MKMapView is not keen on being added to and removed from the view stack.
It's a long shot, but you could try one of the following:
Use setHidden: to temporarily make your map view invisible, in stead of removing and adding it. Not sure, but you might gain a bit of performance from this as well as hiding and showing is probably less expensive than adding and removing...
Use addSubView: and removeFromSuperview to switch your views. This might need some code to provide for setting the framing of the views right or have a "default" frame handy that you can use when you add a view.
Bottom line MKMapView is wrapper around WebView, which sometimes seems to behave a bit odd.
This Map Kit is a bit buggy sometimes, changing my way of presenting views solved the problem.

NSAnimation looping

I've a view that starts an animation when the user drag files on it. The animation shows the files' relative icon (inside an NSImageView Ivar of the NSAnimation custom class) going bigger while fading.
If I loop the animation inside a standard loop like:
CustomAnimation *animation = [[CustomAnimation alloc] initWithDuration: 2.0 animationCurve: NSAnimationLinear]
NSimage *icon;
for (NSString *filename in filenames) {
icon = [[NSWorkspace sharedWorkspace] iconForFile: filename];
NSImageView *myImageView = [[NSImageView alloc] initWithFrame: theFrame];
[myImageView setImage: icon];
[animation setImageView: myImageView];
[animation startAnimation];
}
The loop is too fast and the animations looks like if it were fired almost together (obviously).
What do you think is the best approach to loop an animation several times controlling the delay between the start of one animation and the subsequent?
The reason why your animation blaze by (except perhaps the last one) is that at each iteration your are "overwriting" the previous animation with a new one.
This post on chaining core animations together should do the trick if the idea is to have each animation take the full 2s. You can event add gaps between the animations.
-- Edit --
#Richard that's my mistake, I've misread the question.
A look at the documentaton for NSAnimation suggests that you might use startWhenAnimation:reachesProgress: to chain your animations though.
You can use NSTimer for that purposes.

How can I disable Cocoa's default animation when displaying a modal sheet?

I would like to disable the animation that Cocoa performs when displaying a modal sheet.
Apple's Sheet Programming Guide states:
... Other sheet behavior, such as the animation when it appears and is dismissed, is handled automatically by the Application Kit.
But it doesn't provide any hints on how to disable this effect.
I have created a custom sheet (a subclass of NSWindow with a transparent background and some controls in it). I am able to display it using the standard beginSheet method as follows:
[NSApp beginSheet:myCustomSheet
modalForWindow:mainWindow
modalDelegate:self
didEndSelector:...];
The sheet displays fine, but it goes through an animation when it appears, and again when it closes.
Note: I am writing a completely customized user interface for a touch screen / kiosk type app, so none of the usual Apple user interface guidelines apply.
This is a wild guess (I'm too lazy to try it) but the animation might be handled using Core Animation. If so, you might be able to do this:
[CATransaction begin];
[CATransaction setValue: [NSNumber numberWithBool: YES]
forKey: kCATransactionDisableActions ];
[NSApp beginSheet:myCustomSheet
modalForWindow:mainWindow
modalDelegate:self
didEndSelector:...];
[CATransaction commit];
There is a user default for the animation speed of sheets. Look it up and see what happens if you try to set it to 0.
Override animationResizeTime: in the NSWindow you're presenting as a sheet and have it return 0. This is better than messing with CATransaction (which doesn't seem to work reliably) or NSWindowResizeTime (which affects all windows).

Resources