I'm trying to make a smooth cross fade between 2 movies in my iPad App. On a button tap the visuals randomize & the movie which is playing fades to the next movie.
Since 2 movies cannot be played simultaneously (from the docs) a straight-forward cross-fade isn't possible. To get around this I use a still image of the initial frame of the new movie (which is to be faded in). I used two players to handle the interchange of movies.
The original movie is paused, Then I transition to the image. Now I add my 2nd movie (with alpha = 0.0) & then transition so that its alpha = 1. I then play the new movie. This all works ok except for a noticeable darkening as the new movie transitions in over the image.
I tested it without the still image & the darkening doesn't seem to occur during said transition.
My code for the switch is below (first half of the if-statement). It looks pretty strange ,looking over it, but it's the method that brought me closest to what I needed.
Maybe there's a better way to go about this task? Thanks in advance :)
- (void) switchMovie;
{
NSURL *movieImageUrl = [movieImageUrlArray objectAtIndex:index];
NSData *data = [NSData dataWithContentsOfURL:movieImageUrl];
UIImage *movieImage = [[UIImage alloc] initWithData:data];
UIImageView *image = [[UIImageView alloc] initWithImage:movieImage];
image.alpha = 0.0f;
[self addSubview:image];
if (moviePlayer1Playing) {
moviePlayer1Playing = NO;
moviePlayer2Playing = NO;
[moviePlayer1 pause]; //pausing later in the method caused a crash, stopping causes a crash.
[UIView animateWithDuration:1.0
delay:0.0
options:UIViewAnimationCurveEaseIn
animations:^{
image.alpha = 1.0f; //fade in still of first frame of new movie
} completion:^(BOOL finished) {
[moviePlayer1 release]; //release original movie.
moviePlayer2 = [[MPMoviePlayerController alloc] initWithContentURL:[movieUrlArray objectAtIndex:index]];
moviePlayer2.shouldAutoplay = NO;
[moviePlayer2 prepareToPlay];
[moviePlayer2 setControlStyle:MPMovieControlStyleNone];
moviePlayer2.scalingMode = MPMovieScalingModeAspectFill;
[moviePlayer2.view setFrame:CGRectMake(0, 0, 1024 , 768)];
moviePlayer2.view.backgroundColor = [UIColor clearColor];
moviePlayer2.view.alpha = 0.0;
[self addSubview:moviePlayer2.view];
[UIView animateWithDuration: 3.0
delay: 0.0
options: UIViewAnimationCurveLinear
animations:^(void){
moviePlayer2.view.alpha = 1.0f;
//During this transition the view goes dark half-way through, before lightening again.
} completion:^ (BOOL finished) {
[moviePlayer2 play];
moviePlayer2Playing = YES;
moviePlayer1Playing = NO;
}];
}];
}
The black you see is the background of the movie player, so instead of using a UIImageView for the still, you should set the background of your movie player the desired still.
UIImageView *stillImageView = [UIImageView alloc]initWithImage:stillImage];
stillImageView.frame = self.moviePlayer.backgroundView.frame;
[self.moviePlayer.backgroundView addSubview:stillImageView];
[stillImageView release];
Related
How can I record a video for a certain period of time from a UIView just like we are recording a portion of the phone's screen?
use Glimpse
Glimpse allows you to create videos from UIViews. More documentation is here, but basically it records animations and actions as they happen by taking screen shots of a UIView in a series and then creating a quicktime video and saving it to your app’s document folder.
Here is a sample usage:
#import <Glimpse/Glimpse.h>
#implementation myViewController
- (void)viewDidAppear
{
[super viewDidAppear:animated];
// Create a new Glimpse object.
Glimpse *glimpse = [[Glimpse alloc] init];
// Start recording and tell Glimpse what to do when you are finished
[glimpse startRecordingView:self.view onCompletion:^(NSURL *fileOuputURL) {
NSLog(#"DONE WITH OUTPUT: %#", fileOuputURL.absoluteString);
}];
// Create a subview for this example
UIView *view = [[UIView alloc] initWithFrame:CGRectInset(self.view.bounds, 40.0f 40.0f)];
view.backgroundColor = [UIColor greenColor];
view.alpha = 0.0f;
[self.view addSubview:view];
// We are going to record the view fading in.
[UIView animateWithDuration:5.0 animations:^{
view.alpha = 1.0f;
} completion:^(BOOL finished) {
// Since our animation is complete, lets tell Glimpse to stop recording.
[glimpse stop];
}];
}
#end
I have an imageView in top of my screen, and what i want is - to switch images with specific time interval, and to make it with animation (I'm not specify what really animation should be, that could be fade for example). I have suggested to add that code snippet:
// load all the frames of our animation
self.imageSlideshow.animationImages = [NSArray arrayWithObjects:
self.firstImageIps, self.secondImageIps, self.thirdImageIps, self.fourthImageIps, self.fifthImageIps, nil];
// all frames will execute in 1.75 seconds
self.imageSlideshow.animationDuration = 1.75;
// repeat the animation forever
self.imageSlideshow.animationRepeatCount = 0;
// start animating
NSLog(#"that one called?");
[self.imageSlideshow startAnimating];
But images here only switching, without any animation.
And here is more serious issues - if i set duration to more, then 3 seconds, it start act weird (not of all images show, first image show more often then second and third. It look like it can't achieve a full cycle and move to first image after some short time again and again).
How to achieve switching images with animation, with timer interval, for example 5-7 seconds?
Any advice would be appreciated, thanks!
Try this one:
- (void)viewDidLoad {
[super viewDidLoad];
self.imgArr = [[NSArray alloc] initWithObjects:#"DSC06715.JPG",#"Snapshot_20121113_18.JPG",#"IMAG1689.jpg",#"IMAG1720.jpg",#"IMAG1396.jpg", nil];
[NSTimer scheduledTimerWithTimeInterval:2.5 target:self selector:#selector(performTransition) userInfo:nil repeats:YES];
}
-(void)performTransition
{
int randImg = arc4random()%self.imgArr.count;
[self.imageView1 setImage:[UIImage imageNamed:[self.imgArr objectAtIndex:randImg]]];
CATransition *transition = [CATransition animation];
transition.duration = 1;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
NSString *types[4] = {kCATransitionFade};
transition.type = types[1];
transition.delegate = self;
[self.imageView1.layer addAnimation:transition forKey:nil];
}
-(void)animateImages
{
count++;
[UIView transitionWithView:imageSlideshow
duration:2.0f
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^{
imageSlideshow.image = [imagesArray objectAtIndex: count % [imagesArray count]];
} completion:^(BOOL finished) {
[self animateImages];
}];
}
This code snippet will help you to add any type of animation.
One of the simplest ways to do animation.
Code example :
[UIView animateWithDuration:0.3 animations:^{
//change alpha with animation.
self.friendsTableView.alpha = 1.f;
} completion:^(BOOL finished) {
}];
This animation could be set with delay and optionsas well. As far as i know it is the simplest way to set proper animation with less afford.
To make animation between 2 view you may use spacial UIView method:
- (void)makeCrossDissolveAnimation {
NSArray *images = self.imageSlideshow.animationImages;
static int counter = 0;
UIImageView *startView = [[UIImageView alloc] initWithImage:images[counter]];
counter = (counter+1) % [images count];
UIImageView *endView = [[UIImageView alloc] initWithImage:images[counter]];
[UIView transitionFromView:startView toView:endView duration:ELAnimationDuration
options:UIViewAnimationOptionTransitionCrossDissolve
completion:^(BOOL finished) {
// Your completion block
}];
}
today I decided to make my own animations instead of using UINavigationController's ones; so I've designed an animation (afterwards pseudocode), however I stumbled when I started to write the code. I've thought it will be good if I can make a class hence I can share it.
Let me explain it with words at first, there are two view controllers, when pushing the latter view controller former view controller's view should be blurred, then latter's blurred image should come into. Former's blurred image should go hidden and finally the blur of the latter image should resolve to show the latter view controller properly.
I've got the former VC's image properly with [UIImage convertViewToImage], however I couldn't get the latter VC's image.
I have to push new VC if I want to get snapshot of it with same logic, but you may understand it doesn't seem optimized and practical.
Let me show the code:
- (void)makeLastBackgroundBlur
{
self.lastBackgroundView = [[UIImageView alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIImage *image = [[UIImage convertViewToImage] applyBlurWithRadius:5.0
tintColor:[UIColor colorWithWhite:0.2
alpha:0.7]
saturationDeltaFactor:1.8
maskImage:nil];
self.lastBackgroundView.image = image;
self.lastBackgroundView.alpha = 0;
[self addSubview:self.lastBackgroundView];
}
- (void)makeNextBackgroundBlur
{
self.nextBackgroundView = [[UIImageView alloc] initWithFrame:[UIScreen mainScreen].bounds];
// The part I couldn't do
UIImage *image = [theImageOfTheLatterVC applyBlurWithRadius:5.0
tintColor:[UIColor colorWithWhite:0.2
alpha:0.7]
saturationDeltaFactor:1.8
maskImage:nil];
self.nextBackgroundView.image = image;
self.nextBackgroundView.alpha = 1;
self.nextBackgroundView.hidden = YES;
[self addSubview:self.nextBackgroundView];
}
- (void)invokeAnimation
{
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
// Invoke the blurred background with animation
[UIView animateWithDuration:(self.duration / 2.00)
animations:^{
self.lastBackgroundView.alpha = 1.0f;
}
completion:^(BOOL finished){
self.nextBackgroundView.hidden = NO;
[UIView animateWithDuration:(self.duration / 2.00)
animations:^{
self.nextBackgroundView.alpha = 0;
} completion:^(BOOL finished){
self.lastBackgroundView = nil;
}];
}];
}
This has been asked before but none of the answers are straightforward enough to help little old me.
What exactly does .isAnimating in an UIIimage view do? And how to properly use it?
I am emulating the tap to focus animation in the iPhone camera (yellowish square that pops up and then shrinks when you tap on the preview). That works fine, but I want it to not happen multiple times if it is already animating. This code does the animation but multiple taps gives multiple animationed squares. I suspect it is not just .isAnimating but I'm also doing something else wrong because I tried it with my own boolean too and that fails.
-(void)focusSquarePopUp:(CGPoint)touchPoint;
{
UIImage *focusSquareImage = [UIImage imageNamed:#"yellowFocusSquare"];
UIImageView *tmpView = [[UIImageView alloc] initWithImage:focusSquareImage];
if (!(tmpView.isAnimating))
{
tmpView.center = touchPoint;
tmpView.opaque = YES;
tmpView.alpha = 1.0f;
[self.view addSubview:tmpView];
tmpView.hidden = NO;
// shrink to half size in .3 second
[UIView animateWithDuration:0.3 delay:0 options:0 animations:^{
tmpView.transform = CGAffineTransformMakeScale(.5, .5);
NSLog(#"in animation isAnimating %hhd", tmpView.isAnimating);
} completion:^(BOOL finished) {
// Once the animation is completed hide the view for good
tmpView.hidden = YES;
}];
}
NSLog(#"done animating isAnimating %hhd", tmpView.isAnimating);
[tmpView release];
}
If there is question where this has a solid answer, that would be great.
EDIT - here is the working code.
-(void)focusSquarePopUp:(CGPoint)touchPoint;
{
if (animationInProgress)
return;
animationInProgress = true;
UIImageView *tmpView = [[UIImageView alloc] initWithImage:sp_ui->focus_square];
tmpView.center = touchPoint;
tmpView.opaque = YES;
tmpView.alpha = 1.0f;
[self.view addSubview:tmpView];
tmpView.hidden = NO;
// shrink to half size in .3 second
[UIView animateWithDuration:0.3 delay:0 options:0 animations:^{
tmpView.transform = CGAffineTransformMakeScale(.5, .5);
} completion:^(BOOL finished) {
// Once the animation is completed hide the view for good
tmpView.hidden = YES;
animationInProgress = false;
}];
[tmpView release];
}
I suspect on your code. On your tapping on method focusSquarePopUp: you create new instances of tmpView and focusSquareImage and it adding on self view. That why you found number of animated square equal to number of tap. When you create new instance of those variable then sure isAnimating is firstly you got NO value and it enter animation block code.
Why not you create instance of tmpView and focusSquareImage in .h file of class?? In fact its problem of variable declarations and scope of variables.
Your code should be like this,
Declare instance in animation class (i.e. self.view) .h file
UIImage *focusSquareImage;
UIImageView *tmpView;
Now in .m file viewDidLoad method,
in viewDidLoad
focusSquareImage = [UIImage imageNamed:#"yellowFocusSquare"];
tmpView = [[UIImageView alloc] initWithImage:focusSquareImage];
Your animation method implementation should be,
-(void)focusSquarePopUp:(CGPoint)touchPoint;
{
if (!(tmpView.isAnimating))
{
tmpView.center = touchPoint;
tmpView.opaque = YES;
tmpView.alpha = 1.0f;
[self.view addSubview:tmpView];
tmpView.hidden = NO;
// shrink to half size in .3 second
[UIView animateWithDuration:0.3 delay:0 options:0 animations:^{
tmpView.transform = CGAffineTransformMakeScale(.5, .5);
NSLog(#"in animation isAnimating %hhd", tmpView.isAnimating);
} completion:^(BOOL finished) {
// Once the animation is completed hide the view for good
tmpView.hidden = YES;
[tmpView release];
}];
}
}
Another option of method implementation,
-(void)focusSquarePopUp:(CGPoint)touchPoint;
{
if(!tmpView){
focusSquareImage = [UIImage imageNamed:#"yellowFocusSquare"];
tmpView = [[UIImageView alloc] initWithImage:focusSquareImage];
if (!(tmpView.isAnimating))
{
tmpView.center = touchPoint;
tmpView.opaque = YES;
tmpView.alpha = 1.0f;
[self.view addSubview:tmpView];
tmpView.hidden = NO;
// shrink to half size in .3 second
[UIView animateWithDuration:0.3 delay:0 options:0 animations:^{
tmpView.transform = CGAffineTransformMakeScale(.5, .5);
NSLog(#"in animation isAnimating %hhd", tmpView.isAnimating);
} completion:^(BOOL finished) {
// Once the animation is completed hide the view for good
tmpView.hidden = YES;
[tmpView release];
tmpView = nil;
}];
}
}
}
isAnimating is UIImageView property and it has nothing to do with UIView animation methods
isAnimating is used when you want a UIImageView to alternate between multiple images. For example in the following code the UIImageView display 3 images and alternate between them
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 40, 40)];
UIImage *image1 = [UIImage imageNamed:#"image1.png"];
UIImage *image2 = [UIImage imageNamed:#"image2.png"];
UIImage *image3 = [UIImage imageNamed:#"image3.png"];
imageView.animationImages = #[image1, image2, image3];
imageView.animationDuration = 1;
NSLog(#"isAnimating %d",imageView.isAnimating); // isAnimating 0
[imageView startAnimating];
NSLog(#"isAnimating %d",imageView.isAnimating); // isAnimating 1
[self.view addSubview:imageView];
Your case is completely different you are using UIView animation blocks and to know if the animation in its block is finished or not you will need to add a Boolean flag instance variable animationFinished and set it to YES in the completion block of the animation
I am trying to give the flip effect to a UIview as if on one side I had some content and on the other side I had some other in the following way:
[UIView transitionWithView:FlipView duration:0.7
options:UIViewAnimationOptionTransitionFlipFromRight animations:^{
//imageView.image = secondImage;
FlipImage.hidden = YES;
for (UIButton *btn in arrayoflabels) {
btn.hidden = YES;
}
containerViewSplashit.hidden = NO;
containerViewSplashit.alpha = 1.0;
closeButton.hidden = NO;
} completion:nil];
The only problem is that it flips and then when it finishes flipping, it shows the hidden content I want to show, but it doesn't give that front to back effect that it swops side when it passes the middle. how can i fix this?
You should try to ad the UIViewAnimationOptionAllowAnimatedContent option to the animation option because you have animatable changes in your block (hidden, alpha).