I have a situation where I have to rotate the image like a coin. I am doing as follows.
CATransition* transition = [CATransition animation];
transition.startProgress = 0;
transition.endProgress = 1.0;
transition.type = #"flip";
transition.subtype = #"fromRight";
transition.duration = 1.0;
transition.repeatCount = 15;
[rotateimageView.layer addAnimation:transition forKey:#"transition"];
It is rotating the image but it is not completely rotating it Please check the video.
https://www.dropbox.com/s/x4t2aqyscgecqfb/animationVideo.mov?dl=0
It looks like rotating but the right pointing arrow never points left. I want it to point left and right as a complete coin animation.
Check out the following article in which I explained how to rotate a banner. Maybe you can apply the same techniques in your application.
http://highoncoding.com/Articles/876_Creating_a_Flipping_Tweets_View.aspx
-
(void) updateFlippingView:(NSTimer *) timer
{
if(index == ([tweets count] -1))
{
index = 0;
}
UILabel *messageLabel = (UILabel *) [flippingView viewWithTag:MESSAGE_LABEL_TAG];
[UIView animateWithDuration:1.0 animations:^{
[UIView animateWithDuration:2.0 animations:^{
messageLabel.alpha = 0.0;
} completion:^(BOOL finished) {
[UIView animateWithDuration:1.0 animations:^{
messageLabel.alpha = 1.0;
messageLabel.text = [tweets objectAtIndex:index];
}];
}];
flippingView.layer.transform = CATransform3DMakeRotation(rotationIndex *M_PI, 1.0, 0.0, 0.0);
for(UIView *subView in flippingView.subviews)
{
subView.layer.transform = CATransform3DMakeRotation(rotationIndex *M_PI, 1.0, 0.0, 0.0);
}
}
completion:^(BOOL finished) {
rotationIndex = rotationIndex == 1 ? 2 :1;
}];
index++;
}
Related
I'm developing an IOS app using objective-c. I came across with an instability problem when animating a view's constraints. The animation works well regarding the final position of the frame, but randomly, the trailing(right) constraint is omitted for the first animation block(left constraint never reach to -20 constant value), however leading(left), top and bottom constraints are working as expected.
Please see the video I uploaded. In the first tap, the animation is working as expected, but in the second tap the issue occurs. Please advice.
Video showing the problem
- (void)animateTransition:(nonnull id<UIViewControllerContextTransitioning>)transitionContext {
// 1
UIView *containerView = transitionContext.containerView;
UIViewController* toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
// 2
[containerView addSubview:toViewController.view];
if([toViewController isKindOfClass:[ImageViewController class]]){
ImageViewController *vcImage = (ImageViewController*)toViewController;
vcImage.constraintLeft.constant = 20;
vcImage.constraintTop.constant = self.selectedCardFrame.origin.y + 60.0;
vcImage.constraintRight.constant = 20.0;
vcImage.constraintBottom.constant = 0;//self.CollectionView.bounds.size.height - (self.selectedCardFrame.origin.y + self.selectedCardFrame.size.height);
[toViewController.view layoutIfNeeded];
NSTimeInterval duration = [self transitionDuration:transitionContext];
[toViewController.view layoutIfNeeded];
[UIView animateWithDuration:duration animations:^{
//First animation block
vcImage.constraintRight.constant = -20.0;
vcImage.constraintLeft.constant = -20.0;
vcImage.constraintTop.constant = -20.0;
vcImage.constraintBottom.constant = 0;
[toViewController.view layoutIfNeeded];
//toViewController.configureRoundedCorners(shouldRound: false)
} completion:^(BOOL finished) {
//Second animation block
[UIView animateWithDuration:duration animations:^{
vcImage.constraintLeft.constant = 0;
vcImage.constraintTop.constant = 0.0;
vcImage.constraintRight.constant = 0;
vcImage.constraintBottom.constant = 0;
[toViewController.view layoutIfNeeded];
//toViewController.configureRoundedCorners(shouldRound: false)
} completion:^(BOOL finished) {
[transitionContext completeTransition:finished];
}];
}];
}
}
Updated code after #Sh_Khan 's comment.
- (void)animateTransition:(nonnull id<UIViewControllerContextTransitioning>)transitionContext {
// 1
UIView *containerView = transitionContext.containerView;
UIViewController* toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
// 2
[containerView addSubview:toViewController.view];
if([toViewController isKindOfClass:[ImageViewController class]]){
ImageViewController *vcImage = (ImageViewController*)toViewController;
NSTimeInterval duration = [self transitionDuration:transitionContext];
[UIView animateWithDuration:0 animations:^{
vcImage.constraintLeft.constant = 20;
vcImage.constraintTop.constant = self.selectedCardFrame.origin.y + 60.0;
vcImage.constraintRight.constant = 20.0;
vcImage.constraintBottom.constant = 0;
[toViewController.view layoutIfNeeded];
} completion:^(BOOL finished) {
[UIView animateWithDuration:duration animations:^{
//First animation block
vcImage.constraintRight.constant = -20.0;
vcImage.constraintLeft.constant = -20.0;
vcImage.constraintTop.constant = -20.0;
vcImage.constraintBottom.constant = 0;
[toViewController.view layoutIfNeeded];
//toViewController.configureRoundedCorners(shouldRound: false)
} completion:^(BOOL finished) {
//Second animation block
[UIView animateWithDuration:duration animations:^{
vcImage.constraintLeft.constant = 0;
vcImage.constraintTop.constant = 0.0;
vcImage.constraintRight.constant = 0;
vcImage.constraintBottom.constant = 0;
[toViewController.view layoutIfNeeded];
//toViewController.configureRoundedCorners(shouldRound: false)
} completion:^(BOOL finished) {
[transitionContext completeTransition:finished];
}];
}];
}];
}
}
Before setting your imageView try reorienting the photo. Something tells me the image view is having a hard time determining the orientation of the image. I had this happen during a transition once and would explain why you are seeing the behavior only some of the time. I am a bit rusty with Objective C but give this a shot and use it to before setting your imageView image.
-(UIImage*)normalizeImage:(UIImage*)currentImage {
if (currentImage.imageOrientation == UIImageOrientationUp){
return currentImage;
}
UIGraphicsBeginImageContextWithOptions(currentImage.size, NO, currentImage.scale);
[currentImage drawInRect:CGRectMake(0, 0, currentImage.size.width, currentImage.size.height)];
UIImage *_newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return _newImage;
}
In UINavigationController Delegate I add pop animation in the transition, what I did is as following:
- (NSTimeInterval) transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext {
return self.duration;
}
- (void) animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
UIView *containerView = [transitionContext containerView];
UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
// I get some cell from initialization
UIImageView *avatarImage = [[UIImageView alloc] initWithFrame:frame];
avatarImage.image = _cell.avatarImageView.image;
avatarImage.clipsToBounds = YES;
avatarImage.layer.cornerRadius = avatarImage.frame.size.width/2.0;
CGFloat originSize = avatarImage.frame.size.width;
[fromViewController.view addSubview:avatarImage];
CGFloat avatarSize = CURRENT_SCREEN_WIDTH * 0.15;
CGFloat avatarPositionY = CURRENT_SCREEN_WIDTH * 0.4;
POPSpringAnimation *animation = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerPosition];
animation.toValue = [NSValue valueWithCGPoint:CGPointMake(CURRENT_SCREEN_WIDTH/2.0, avatarPositionY + avatarSize/2.0 - 64)];
animation.springBounciness = 2.0;
[avatarImage.layer pop_addAnimation:animation forKey:#"move"];
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
toViewController.view.alpha = 1;
} completion:^(BOOL finished) {
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
[imageView removeFromSuperview];
[avatarImage removeFromSuperview];
}];
}
But the problem is, it's not smooth at all, what is the problem ?
There can be multiple problems;
Your image is very big (in memory)
The corner radius isn't helping either
You're doing something else on the main thread during during this animation
Try the following and see if the animation is smooth after each change:
Remove/comment:
avatarImage.image = _cell.avatarImageView.image;
Remove/comment:
avatarImage.clipsToBounds = YES;
avatarImage.layer.cornerRadius = avatarImage.frame.size.width/2.0;
I have two UIImages one over another, with the same size (40 by 40) it's a simple dot on the whole UIImage and I want to animate rotating as a 3D. When the first UIImage "colapse" and it is not visible, change the property HIDDEN to YES, and immediately the UIImage under the first begin to appears, and when the user press the button again everything turn back at the first state. But i works only the first time, after that, just appears and disappears the images.
Heres is my code:
#interface ViewController ()
{
BOOL myFlag;
}
#end
- (void)viewDidLoad {
[super viewDidLoad];
self.C002.image = [Test imageOfCircle002];
self.C005.image = [Test imageOfCircle005];
self.C005.hidden = YES;
myFlag = YES;
}
- (IBAction)animationButton:(id)sender
{
if (myFlag)
{
//First state of the UIImages,
[UIView animateWithDuration:1.0 animations:^{
//3D rotation C002
CABasicAnimation* animation;
animation = [CABasicAnimation animationWithKeyPath:#"transform.rotation.y"];
animation.fromValue = #(0);
animation.toValue = #(0.5 * M_PI);
animation.repeatCount = 1;
animation.duration = 1.0;
[self.C002.layer addAnimation:animation forKey:#"rotation"];
CATransform3D transform = CATransform3DIdentity;
transform.m34 = 1.0 / 500.0;
self.C002.layer.transform = transform;
} completion:^(BOOL finished) {
self.C002.hidden = YES; //Hide the first image
self.C005.hidden = NO; //Show the second and animate
[UIView animateWithDuration:1.0 animations:^{
//3D rotation C005
CABasicAnimation* animation2 = [CABasicAnimation animationWithKeyPath:#"transform.rotation.y"];
animation2.fromValue = #(0.5 * M_PI); //begin where the first UIImage ends
animation2.toValue = #(1.0 * M_PI);
animation2.repeatCount = 1;
animation2.duration = 1.0;
[self.C005.layer addAnimation:animation2 forKey:#"rotation"];
CATransform3D transform2 = CATransform3DIdentity;
transform2.m34 = 1.0 / 500.0;
self.C005.layer.transform = transform2;
} completion:^(BOOL finished) {
[self.C002.layer removeAnimationForKey:#"rotation"];
[self.C005.layer removeAnimationForKey:#"rotation"];
}];
}];
myFlag = NO; // Set the flag to other state.
}
else
{ //Heres try to turn everything back, but... not working.
[UIView animateWithDuration:1.0 animations:^{
//3D rotation C005
CABasicAnimation* animation;
animation = [CABasicAnimation animationWithKeyPath:#"transform.rotation.y"];
animation.fromValue = #(1.0 * M_PI); //begin where is in the last animation
animation.toValue = #(0.5 * M_PI);
animation.repeatCount = 1;
animation.duration = 1.0;
[self.C005.layer addAnimation:animation forKey:#"rotation"];
CATransform3D transform = CATransform3DIdentity;
transform.m34 = 1.0 / 500.0;
self.C005.layer.transform = transform;
} completion:^(BOOL finished) {
self.C005.hidden = YES;
self.C002.hidden = NO;
[UIView animateWithDuration:1.0 animations:^{
//3D rotation C002
CABasicAnimation* animation2 = [CABasicAnimation animationWithKeyPath:#"transform.rotation.y"];
animation2.fromValue = #(0.5 * M_PI);
animation2.toValue = #(0 * M_PI);
animation2.repeatCount = 1;
animation2.duration = 1.0;
[self.C002.layer addAnimation:animation2 forKey:#"rotation"];
CATransform3D transform2 = CATransform3DIdentity;
transform2.m34 = 1.0 / 500.0;
self.C002.layer.transform = transform2;
} completion:^(BOOL finished) {
[self.C002.layer removeAnimationForKey:#"rotation"];
[self.C005.layer removeAnimationForKey:#"rotation"];
}];
}];
myFlag = YES;
}
}
Hope guys, you can help me.
I am having diffuculties about bouncies animation effect , whenever i swipe down, The two UI elements swipe down , 1st is container ( which holds UIPickerView ) and it changes coordinate(x,y) and w/h value, second UI is just for pull on/off and I am only applying it's coordinates. I am doing it with FacebookPOP Framework and i also applied bounce effect. First pulling down , 2 UI has a trailing space while keeping in bounce effect. Without change or refresh view controller, second / third's swipe down action occurs as i expected .
My code while swipe down / up looks like that :
if(sender.direction == UISwipeGestureRecognizerDirectionDown)
{
isDown = YES;
POPSpringAnimation *bounceForControlView = [POPSpringAnimation animation];
bounceForControlView.property = [POPAnimatableProperty propertyWithName:kPOPViewFrame];
bounceForControlView.toValue=[NSValue valueWithCGRect:CGRectMake(0, 241, 320, 42)];
bounceForControlView.springBounciness = 15;
bounceForControlView.springSpeed = 10;
[controlView pop_addAnimation:bounceForControlView forKey:#"bounceForControlView"];
POPSpringAnimation *bounceForPickerView = [POPSpringAnimation animation];
bounceForPickerView.property = [POPAnimatableProperty propertyWithName:kPOPViewFrame];
bounceForPickerView.toValue=[NSValue valueWithCGRect:CGRectMake(0, 64, 320, 177)];
bounceForPickerView.springBounciness = 15;
bounceForPickerView.springSpeed = 10;
[swipeView pop_addAnimation:bounceForPickerView forKey:#"bounceForPickerView"];
[UIView animateWithDuration:0.7 animations:^() {
[pullUPImage setAlpha:1.0];
[self.pullImage setAlpha:0.0];
}];
[UIView animateWithDuration:0.7 animations:^() {
[myPicker setHidden:NO];
}];
}
if(sender.direction == UISwipeGestureRecognizerDirectionUp)
{
isDown = NO;
[myPicker setHidden:YES];
popAnimation = [POPSpringAnimation animation];
popAnimation.property = [POPAnimatableProperty propertyWithName:kPOPViewFrame];
popAnimation.toValue=[NSValue valueWithCGRect:CGRectMake(0, 64, 320, 0)];
popAnimation.springBounciness = 5;
popAnimation.springSpeed = 5;
[swipeView pop_addAnimation:popAnimation forKey:#"slide"];
popAnimation = [POPSpringAnimation animation];
popAnimation.property = [POPAnimatableProperty propertyWithName:kPOPViewFrame];
popAnimation.toValue=[NSValue valueWithCGRect:CGRectMake(0, 64, 320, 42)];
popAnimation.springBounciness = 5;
popAnimation.springSpeed = 5;
[controlView pop_addAnimation:popAnimation forKey:#"slide"];
[UIView animateWithDuration:0.5 animations:^() {
[pullUPImage setAlpha:0.0];
[self.pullImage setAlpha:1.0];
}];
}
This is how animation works in realtime :
Here is a transition code I have for Showing ViewB from ViewA
CGPoint c = thepoint;
CGFloat tx = c.x - floorf(theview.center.x) + 10;
CGFloat ty = c.y - floorf(theview.center.y) + 100;
[UIView animateWithDuration:0.5
delay:0.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
// Transforms
CGAffineTransform t = CGAffineTransformMakeTranslation(tx, ty);
t = CGAffineTransformScale(t, 0.1, 0.1);
theview.transform = t;
theview.layer.masksToBounds = YES;
[theview setTransform:CGAffineTransformIdentity];
}
completion:^(BOOL finished) {
}];
Now that the transition went very smooth without issues.
When in my ViewB, I had a text box with default focus. (In viewDidAppear)
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:NO];
[self performSelector:#selector(focusCommentText) withObject:nil afterDelay:0.5];
}
- (void) focusCommentText {
[self focusTextbox:commentText];
}
- (void) focusTextbox : (UITextView *) textView{
#try {
[ textView becomeFirstResponder];
}
#catch (NSException *exception) {
}
}
The Transition and the Keyboard coming up.. happens at same time.. And it is slightly awkward now. Can some one help me out here please?
What I would do is not call [textView becomeFirstResponder] until after the transition has completed.
EDIT: The killer was actually the background color of my view was transparent with alpha 0.8. Once I made it opaque (alpha = 1.0), the animation was smooth!!
I modified my code to make the focus of text box only after completion of the animation.
CGPoint c = thepoint;
CGFloat tx = c.x - floorf(theview.center.x) + 10;
CGFloat ty = c.y - floorf(theview.center.y) + 100;
[UIView animateWithDuration:0.5
delay:0.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
// Transforms
CGAffineTransform t = CGAffineTransformMakeTranslation(tx, ty);
t = CGAffineTransformScale(t, 0.1, 0.1);
theview.transform = t;
theview.layer.masksToBounds = YES;
[theview setTransform:CGAffineTransformIdentity];
}
completion:^(BOOL finished) {
if( theview.tag == 1000) {
if(myVC != nil)
[myVC focusCommentText]; /// Here is where I set focus
}
}];
When CATransition is used, it is the delegate animationDidStop I have to choose.
CATransition *transition = [CATransition animation];
transition.duration = 0.4;
transition.type = kCATransitionFromRight; //choose your animation
transition.subtype = kCATransitionFade;
transition.delegate = self; //Setting Delegate as Self
[self.view.layer addAnimation:transition forKey:nil];
[self.view addSubview:myVC.view];
#pragma mark - CATransition Delegate
- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag
{
if(myVC != nil) {
[myVC focusCommentText];
}
}