Transition between NSImageViews in Objective-C - objective-c

I am not very familiar with the Mac OS X APIs (coming from a long background of iPhone sdk) and I was wondering how I could add a transition when I switch nsimageviews. Does anyone have a short code snippet they can share about how to go about doing this?

This tutorial does pretty much the same thing, albeit with some extra things you probably don't need: http://www.cimgf.com/2008/03/03/core-animation-tutorial-wizard-dialog-with-transitions/
In short, just call
[[myWindow contentView] setWantsLayer:YES];
[[[myWindow contentView] animator] replaceSubview:currentView with:newView];
to do a crossfade animation of the two views. If you want to do a different type of animation, the fourth block of code in the tutorial should be of help.
Be warned that using Core Animation layers ruins your font rendering, so you'll probably want to setWantsLayer:NO after the animation is complete also.

Related

iCarousel disables any other animation done in the background

I am using Nick Lockwood's iCarousel to display images, and I need to make a transition between backgrounds behind the carousel when the carousel stops at an image.
I am using UIView's animateWithDuration, and the problem is that the animation completion happens instantly because iCarousel is calling [CATransaction setDisableActions:YES];
I deleted the call to disableAnimation and enableAnimation in Step method of iCarousel, and now my transition animation works fine, but I'm afraid some functionality will be missing or strange bugs will occur now.
can anybody concur or suggest a different approach for this?
The [CATransaction setDisableActions:YES] is partly for Mac support and partly to prevent weird resizing effects when item views are loaded. If you aren't seeing any problems then it's probably safe to disable those lines, but you're generally better off not modifying the library if you don't have to as it makes it more difficult to upgrade to a new release later.
When are you triggering your animation? If you only want it to happen when the carousel comes to a stop, the correct place to do it is probably in the
- (void)carouselDidEndScrollingAnimation:(iCarousel *)carousel;
Delegate method. If you do it there you shouldn't have problems with the animation being stopped. If you are already doing it there, and you are still seeing problems then a workaround is to delay your animation until the next runloop update, which you can do using GCD, like this:
dispatch_async(dispatch_get_main_queue(), ^{
//perform your animation code
});

Drawing a Bar in iPhone / iPad

How can I draw a simple BAR?
Like this:
Thank you.
You'll want to make a UIToolbar, put it at the bottom of your XIB, and put some buttons on it. Now, this will by default give you a regular black bar, with that standard black gloss. If you want to have a custom image, there are two solutions.
First is simply subclass UIToolbar and override its drawRect to draw a custom image. The code for overriding drawRect would look something like this:
//in some other code somewhere, preferably on init
self.image = [UIImage imageNamed: #"image"];
- (void)drawRect:(CGRect)rect {
[self.image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
}
Now, in iOS 5.0 there is something very useful called appearance but you have to be willing to only target 5.x+ iOS versions.
The second, which is simpler but less versatile, is to simply stick a UIImageView at the bottom of the XIB, and place some buttons on top of it. This is much easier than above, but is less extensible, is harder to modify, and is frowned upon in iOS for good reason - it breaks general iOS conventions (and you lose some very useful functionality).
Crimson has a nice idea but since his/her answer requires using UIToolbar, I'll offer an alternative:
Basically what you are showing there is some kind of progress bar, so ultimately whatever you want to display should be something subclassed from UIControl or even better, UIProgressView or maybe a UISlider.
Google around for custom progress view indicators or sliders. There are also good examples available here on Stackoverflow.

Clicking through NSWindow/CALayer

So I'm working on an issue I have when trying to do some simple animation using CAKeyframeAnimation, and I believe my problem is more related to not fully understanding how NSWindow, NSView, and CALayer work together. 
I have two main objects in question. MyContainerWindow (NSWindow subclass) and MyMovableView (NSView subclass). My goal is to be able to animate MyMovableView back and forth across the screen, while maintaining the ability to click on anything through MyContainerWindow unless you are clicking on wherever MyMovableView is. I am able to accomplish the first part fine, by calling -addAnimation:forKeyPath: on myMovableView.layer, and everything is great except I can't click through MyContainerWindow. I could make the window smaller, but then the animation would clip by the bounds of the window.
Important points: 
1) MyContainerWindow is initWithFrame to [[NSScreen mainScreen] frame], NSBorderlessWindowMask, defer no, buffered
2) I setWantsLayer:TRUE to MyMovableView
3) MyContainerWindow is clear, and I want it to be as if there wasnt a window at all, but need it so I have a larger canvas to animate on.
Is there something obvious I'm missing to be able to click through an NSWindow?
Thanks in advance!
My solution in this scenario was actually to use:
[self ignoresMouseEvents:YES];
I originally was hoping to be able to retain the mouse events on the specific CALayer that I'm animating, but upon some further research I understand this comes with the cost of custom drawing everything from scratch, which is not ideal for this particular project.

Disabling buttons before view rotates

So been working on another app recently for iOS which incorporates a UIImagePickerViewController. App is ready to go and all works fine under normal circumstances, but if the user is being eratic and pushing buttons whilst rotating the iPad, then things go slightly awry and views load in the wrong place.
So basically, I want to disable all my buttons before the iPad is rotated and enable them again after the view is done rotating.
I thought this would be easy using the
-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
and
-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
methods.
But because the UIImagePickerController is being displayed, this for some reason stops these methods from being called. So I can't use these methods.
So basically, what I'm asking is if anybody can think of any other ways that I could achieve this??
Thanks,
Matt
You could subclass UIImagePickerController and then implement those methods on your UIImagePickerController subclass.

Rotate some UIViews, but not all?

I'm doing an app where I have a GLES view which I don't want to be auto-rotated, and UIKit views on top of that, which do need to be auto-rotated.
Apparently this is not something you're supposed to be doing, as I can't find any good documentation on it. However I'm totally sure this is exactly what I want.
I've found a solution, but it feels hacky:
Create window.
Create some auto-rotated UIViewControllers.
Add their views to the window.
Create an OpenGL ES view controller that's not auto-rotated.
Add its view to the window.
Call bringSubviewToFront: for the auto-rotated views.
Give yourself a high-five, while trying to ignore the nagging feeling that this is actually a nasty hack.
Anyone know of a better solution? NB: I'm absolutely positive that I want to auto-rotate the UIKit views and not the GL view.
Thanks for your time, much appreciated. =)
I've come up with a different strategy for a similar situation. In my case I allow all the views to rotate, but then use a transform to bring the view I want to keep steady back to its original orientation. This works because the "non-rotating" view is square, but with a bit more math it could work for other shapes as well. Here's what I put in my willRotateToInterfaceOrientation:duration:
switch (toInterfaceOrientation) {
case UIInterfaceOrientationPortrait:
steadyView.transform = CGAffineTransformIdentity;
break;
case UIInterfaceOrientationLandscapeLeft:
steadyView.transform = CGAffineTransformMakeRotation(M_PI_2);
break;
case UIInterfaceOrientationPortraitUpsideDown:
steadyView.transform = CGAffineTransformMakeRotation(M_PI);
break;
case UIInterfaceOrientationLandscapeRight:
steadyView.transform = CGAffineTransformMakeRotation(3*M_PI_2);
break;
}
The steadyView is s subview of the controller. This seems to do the trick.
There isn't a good way to do this any better than what you proposed.
Are you sure you don't just want to rotate the OpenGL views too? If your application is limited to the ES 2.0 devices and later on iOS 4.2, there is no longer any performance penalty to using UIViewController rotation for OpenGL views.
Wouldn't it be simpler to just draw your OpenGL content sideways when rotated? Just apply a rotation in your renderer to undo the rotation of OpenGL view.
You may see an unacceptable jump back to the original rotation, but you could address that easily. You could animate the return rotation, once the view is finished rotating. Or you could override willAnimateFirstHalfOfRotationToInterfaceOrientation:duration: and willAnimateSecondHalfOfRotationFromInterfaceOrientation:duration: to animate the content staying in place during the interface rotation.
So I found out how it works behind the scenes; Frogblast is right, there isn't any substantially better way to do it.
What happens is that when a view gets added to a window that has no subviews, that view's controller is automatically the "rotation authority"; If that view controller returns NO from shouldAutorotateToInterfaceOrientation, no other views will rotate either. However, subsequent views (with controllers) added to the window are still allowed not to rotate, even if the "rotation authority" does rotate.
Unclear to me why they've made it like this, but there you have it.