XCode/Objective-C: Simultaneous animations for instances of UIView? - objective-c

I have two IBOutlet variables connected to two instances of UIView in Interface Builder, called blankView and fadedBGView in my ViewController.
How can I set up this code so that the blankView instance will fade into fadedBGView, using the UIViewAnimationOptionTransitionCrossDissolve transition, and the two UIViews can simultaneously transform (move) from their current position (they have equal positions) to 0,0?
What's happening is the fade occurs, and then the fadedBGView view abruptly moves to 0,0.
In other words, I'd like to have the first UIView fade into the second, while simultaneously moving up the screen.
Hopefully this is clear enough to answer.
Best...SL
[UIView transitionFromView:blankView
toView:fadedBGView
duration:1.0
options:UIViewAnimationOptionTransitionCrossDissolve
completion:^(BOOL finished) {
[blankView removeFromSuperview];
}];
[UIView commitAnimations];
CGRect frame = fadedBGView.frame;
frame.origin.x = 0;
frame.origin.y = 0;
[UIView animateWithDuration:1.0 animations:^{
NSLog(#"UIView Transition/Move Called");
fadedBGView.frame = frame;
}];

iOS 4 and newer provides block-based animations, which your code is already using:
+[UIView animateWithDuration:animations:];
+[UIView animateWithDuration:animations:completion:];
Within the animation block, you can set multiple destination values. See Apple's UIView documentation for a reference to the animatable properties. So within one block, you can modify frames, and alpha (transparency) values of views. I'm not sure how the cross dissolve animation works, but if it's simply one view going from 0 to 1, and another view going from 1 to 0, that's easy to implement.

Instead of
UIViewAnimationOptionTransitionCrossDissolve
use
UIViewAnimationOptionTransitionCrossDissolve | UIViewAnimationOptionAllowAnimatedContent
UIViewAnimationOptionAllowAnimatedContent option allows additional animations during transition. Make sure your fadedBGView has correct starting frame.

Related

Smoother transition from one UIView to another UIView

I have a UIViewController which has multiple subviews. Each subview is a UIView subclass, and I want to switch between views by tapping the toolbar buttons. I did this by using the animation blocks:
Example:
[UIView animateWithDuration:0.5
delay:0.0
options:UIViewAnimationOptionTransitionFlipFromRight
animations:^{
[StoreView removeFromSuperview];
[self.view addSubview:HomeView];
}
completion:NULL];
Everything is working fine actually. The problem is the transition is not really smooth. For example, the HomeView has five buttons scattered (as part of the design), and whenever I switch from one view to HomeView, these buttons will come from a corner and rearrange itself after the transition, which is not exactly beautiful to look at.
So how will I make these buttons stay in place?
When doing animations with complex subviews you can sometimes get undesirable results as you are experiencing. Not only can some oddities appear, but they are sometimes costly depending on the complexity of the view structure. One suggestion I would make is instead of animating the complex views themselves, you could render the views to a graphics context and animate the resulting image in a UIImageView, using sleight-of-hand to make it appear that you are animating the view hierarchy. In this effect, you avoid doing what amounts to a complex transform on the HomeView and StoreView and instead do simple flip with UIImageView instances. Consider the following example code:
UIImageView *storeImage = // pointer to the image rendered to a graphics context
UIImageView *homeImage = // pointer to the image rendered to a graphics context
[self.view addSubview:storeImage];
[storeView removeFromSuperview];
[UIView animateWithDuration:0.5
delay:0.0
options:UIViewAnimationOptionTransitionFlipFromRight
animations:^{
[storeImage removeFromSuperview];
[self.view addSubview:homeImage];
}
completion:^(BOOL finished) {
[self.view addSubview:homeView];
[homeImage removeFromSuperview];
}];

Moving a UIView

I am trying to move a UIView programmatically using the following method:
-(void)animatePlaybackLine: (int) currentBeat{
CGRect newFrame = CGRectMake(currentBeat*eighthNoteWidth, 0, eighthNoteWidth, 320);
[playbackLine setFrame:newFrame];
NSLog(#"Line animated to %i", currentBeat);
NSLog(#"New frame origin %f", playbackLine.frame.origin.x);
}
When the method is called, the NSLogs show that the variable currentBeat is incrementing as it should, and the frame of playbackLine (my UIView) appears to be moving as it should. However, the object on the screen doesn't move. I have also tried setting the bounds and the center instead of the frame, and all of them have similar results. I also tried using an animation instead of setting the frame, to no avail.
Is there something else I should be doing to make the image onscreen show the changing frame?
I'm guessing you're calling that method in a loop? iOS isn't going to redraw the screen until your code finishes executing. You can't loop like this and see iterative results.
To animate views, you should use the native support UIKit gives you. In particular, check out the Animations section in the UIView class reference.
Try this
[UIView animateWithDuration:0.3
delay:0.0
options: UIViewAnimationCurveEaseOut
animations:^{
datePickerView.frame = imageFrame;
}
completion:^(BOOL finished){
self.datePickerViewFlag = NO;
}];

Why does view draw under the task bar after a custom scale and flip animation?

Same code as in a previous question, but a different issue.
I've created a custom animation to add a view controller to a UINavigationController. This code scales a view to 80% the original size, then flips it, then scales it back up to its original size:
[UIView animateWithDuration:scaleDuration delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
// Scale the controllers' views down.
self.view.transform = CGAffineTransformScale(self.view.transform, 0.8, 0.8);
} completion:^(BOOL finished) {
// Transition to the new view and push on the new view controller.
[UIView transitionWithView:self.view duration:1 options:UIViewAnimationOptionCurveLinear | UIViewAnimationOptionTransitionFlipFromLeft animations:^{
[self pushViewController:viewController animated:NO];
} completion:^(BOOL finished) {
[UIView animateWithDuration:scaleDuration delay:0 options:UIViewAnimationOptionCurveLinear animations:
^{
// Scale back to the original size.
self.view.transform = CGAffineTransformScale(self.view.transform, 1.25, 1.25);
} completion:nil];
}];
}];
The issue is that, when the animation completes, the new view is displayed very nicely, except that it is drawn under the task bar. That is, it draws in at screen origin 0,0, rather than 0,20. The "Status Bar" option is set in IB (to "Black"), and, naturally, this does not happen if I use a standard UINavigationController push animation, only my custom one. If I rotate the device after the animation, the redraw on rotation moves it to the proper place. But how do I get it to do that in the first place?
As an added wrinkle, it does not draw under the task bar if I move the pushViewController:animated: call a line down to the completion: block (though then the view appears to flip to itself and then suddenly show the new view, of course).
I found the only work around so far is hide the navigationbar and then show it.
after you set your transform, add following 2 lines:
[self setNavigationBarHidden:YES];
[self setNavigationBarHidden:NO];
It's ugly but works, I am also looking for a better solution.
note: layoutsubview, setNeedsLayout won't work.

Consecutive animations using nested animation blocks

I'm looking for a way to implement consecutive animations using nested animation blocks.
Somewhat complicated by happening inside a UIScrollView, the size of three UIImageViews (there are many images, and as I scroll through them I constantly swapping out the images in the UIImageViews).
When a scroll is finished, I want to switch out the image in the (visible) middle UIImageView, three times, then back to the original view. I'm trying it thus:
- (void) doAnimation {
// get the animation frames, along with the current image
NSString *swap1 = #"first.png";
NSString *swap2 = #"second.png";
UIImage *original = currentPage.image;
UIViewAnimationOptions myOptions = UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionAllowUserInteraction;
[UIView animateWithDuration:2.0 delay:2.0 options:myOptions
animations:^{ [currentPage setImage:[UIImage imageNamed:swap1]]; }
completion:^(BOOL finished) {
[UIView animateWithDuration:2.0 delay:2.0 options:myOptions
animations:^{ [currentPage setImage:[UIImage imageNamed:swap2]]; }
completion:^(BOOL finished) {
[UIView animateWithDuration:2.0 delay:2.0 options:myOptions
animations:^{ [currentPage setImage:[UIImage imageNamed:swap1]]; }
completion:^(BOOL finished) {
[currentPage setImage:original]; }]; }]; }];
}
When I run this, there is no duration, no delay, it all happens at once, almost too fast for the eye to see. Could this be because "currentPage" is a UIImageView? (Similar to this question?)
There's no delay because UIImageView.image isn't an animateable property. As such, the UIView animation machinery will have no animations to set up and will just call your completion block immediately.
What sort of animation did you expect? You can attach a CATransition object to the underlying layer to get a simple cross-fade, Just use [imageView.layer addAnimation:[CATransition animation] forKey:nil] to get the crossfade with the default values (you can customize the timing by modifying properties of the CATransition before attaching it to the layer). To achieve the subsequent animations, you can either use the delegate property of CAAnimation (CATransition's superclass) to learn when it's done and fire your second one, or you could just use -performSelector:withObject:afterDelay: to start your next animation step after a user-defined delay. The delegate method is going to be more accurate with regards to timing, but the performSelector method is a bit easier to write. Sadly, CAAnimation doesn't support a completion block.
Another approach for you to transition from one image view to another is by using the block animation function transitionFromView:toView:duration:options:completion as discussed in "Creating Animated Transitions Between Views". You would do this instead of animateWithDuration to change images.

How to implement the effect of popping up tableview from bottom of screen?

I'm a newbie of Xcode and Objective-c. Recently I wanna do a task about popping up tableviews. When a button is pressed, the tableview should pop up from the bottom of the screen. The tableview will contain just a few items so I don't wanna it occupy full screen. I read the manual and found UIModalPresentationStyle, but it seems not fulfill my requirements. So what's the more accurate methods I can use?
While #Bharat J's answer is correct, those methods are deprecated in iOS 4.0.
The latest and greatest implementation is + (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations
Implemented as:
[UIView animateWithDuration:0.5 animations: ^{
tableView.frame = newFrame;
}
];
You can use below code to create an animation block . Set the frame for the table view as (0,480,320,0) When you hit a button change the frame of the table view in the animation block and make it to CGRectMake(0,200,320,280) or something .
[UIView beginAnimations:#"AnimateTableView" context:view];
[UIView setAnimationDuration:0.5];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
tableView.frame = CGRectMake(0, 200 , 320, 280);
[UIView commitAnimations];
The same animation block for hiding it again but with the frame again begin set to CGRectMake(0,480,320,0). This should work in your case .
Another option would be to use a UIActionSheet and add the uitableview as a subview.
Here is a very similar question about how to add a UIPickerview with similar effect.
Add UIPickerView & a Button in Action sheet - How?