iPhone : UIVIew Boing kind of animation - iphone

Sorry for the poor title, I am trying to think of a easy way to explain this.
I have a UIView in the center of the screen which contains a progress indicator and background image.
What I want it to do is get bigger to a certain point and then shrink a tiny bit. So it "boings" in.
I had a play with normal UIView animations etc and have it coming in. However I thinking to get this to work well I need to use the views layer. The main issue at the moment is the indicator does not size.
Has anyone done a boing effect on a view?

Something like this?
- (void)boingView:(UIView *)theView {
[UIView animateWithDuration:0.1 animations:^(void) {
theView.transform = CGAffineTransformMakeScale(1.3, 1.3);
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.1 animations:^(void) {
theView.transform = CGAffineTransformMakeScale(0.8, 0.8);
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.1 animations:^(void) {
theView.transform = CGAffineTransformMakeScale(1.0, 1.0);
} completion:nil];
}];
}];
}

Related

Block not being called and not animating in IOS 7

I am using ShakingAlertView in my app.
https://github.com/lukestringer90/ShakingAlertView
It works perfectly in IOS 6. But after i updating to IOS 7 it didnt animate and the block function for incorrect handing not being called.
Given below is the code for the initialization of shaking alert view.
currentPass = [[ShakingAlertView alloc]initWithAlertTitle:#"Enter Current Password" checkForPassword:self.pass
usingHashingTechnique:HashTechniqueMD5
onCorrectPassword:^{
isCurrentPassConfirmed = YES;
[self._accountSource willScrollToTop];
self.password.text = #"";
[self.password becomeFirstResponder];
} onDismissalWithoutPassword:^{
//NSLog(#"hi");
[self showFailedPasswordAlert];
}];
currentPass.alertViewStyle = UIAlertViewStyleSecureTextInput;
[currentPass show];
Below is the method to animate for shake effect.This is invoked correctly but there is no effect.
- (void)animateIncorrectPassword {
// Clear the password field
_passwordField.text = nil;
// Animate the alert to show that the entered string was wrong
// "Shakes" similar to OS X login screen
CGAffineTransform moveRight = CGAffineTransformTranslate(CGAffineTransformIdentity, 20, 0);
CGAffineTransform moveLeft = CGAffineTransformTranslate(CGAffineTransformIdentity, -20, 0);
CGAffineTransform resetTransform = CGAffineTransformTranslate(CGAffineTransformIdentity, 0, 0);
[UIView animateWithDuration:0.1 animations:^{
// Translate left
self.transform = moveLeft;
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.1 animations:^{
// Translate right
self.transform = moveRight;
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.1 animations:^{
// Translate left
self.transform = moveLeft;
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.1 animations:^{
// Translate to origin
self.transform = resetTransform;
}];
}];
}];
}];
}
Please help me.
iOS7 does not allow you to customize the UIAlertview.
Better create the custom view subclass of UIView which is draw the
view programmatically using - (void)drawRect:(CGRect)rect method.
And create one more container class(inherited from NSObject) which
is used to create and bind your title/password and OK buttons
with your custom delegate property into your customized alert
view.So that we can implement our custom delegate method as like
clickedButtonAtIndex method.
Upto my knowledge there is no changes in block/animation in iOS7.
Or refer this link https://github.com/wimagguc/ios-custom-alertview
The layout of UIAlertView changed drastically is iOS 7, making it almost impossible to customise and alter. You're going to have to come up with a new solution.

Problems animating UIView alpha

I'm trying to apply a fade to an UIView I created programmatically on the top of another.
[UIView animateWithDuration:0.5 animations:^(void) {
[self.view setAlpha:0];
}
completion:^(BOOL finished){
[self.view removeFromSuperview];
}];
The finished event is called properly after exactly 0.5 seconds, but I don't see any fade (I should see the UIView on the bottom).
If instead of using the alpha, I move away the UIView it works (I see the bottom UIView while the top UIView slides away), so it seems to be a problem related to alpha, but I can't figure out what's wrong!
[UIView animateWithDuration:0.5 animations:^(void) {
CGRect o = self.view.frame;
o.origin.x = 320;
self.view.frame = o;
}
completion:^(BOOL finished){
[self.view removeFromSuperview];
}];
I used alpha animations previously and they works in this way usually...
Try setting opaque to NO explicitly. I had the same problem and setting that solved my problem. Apparently, opaque views just don't seem to play well with alpha.
Credit goes to Hampus Nilsson's comment though.
I experience same issue in my case its because of thread
So i end up with write animation block in main thread.
dispatch_async(dispatch_get_main_queue(), ^{
[UIView animateWithDuration:2 delay:0 options:UIViewAnimationOptionLayoutSubviews animations:^{
View.alpha = 0.0f;
} completion:^(BOOL finished) {
}];
});
[UIView animateWithDuration:0.6 delay:0 options:UIViewAnimationOptionCurveEaseInOut
animations:^{
[self.view setAlpha:0];
}
completion:^(BOOL finished) {
[self.view removeFromSuperview];
}];
This will work right, and your fading will be nicer, because of options:UIViewAnimationOptionCurveEaseInOut.
I ran into the exact problem. In my case, I wanted the view to be hidden at first, so I set hidden to true. I thought changing the alpha value changes hidden property automatically, but that wasn't the case.
So, if you want the view to be hidden at first, set its alpha to 0.
I had exactly the same problem, and none of the suggestions worked for me. I overcame the problem by using the layer opacity instead.
This is the code for showing the layer (using Xamarin, but you'll get the idea):
//Enter the view fading
zoomView.Layer.Opacity = 0;
UIApplication.SharedApplication.KeyWindow.RootViewController.View.Add(zoomView);
UIView.AnimateNotify(
0.15, // duration
() => { zoomView.Layer.Opacity = 1.0f },
(finished) => { }
);
And this is for fading out the same zoomView
UIView.AnimateNotify(
0.15, // duration
() => { zoomView.Layer.Opacity = 0; },
(finished) =>
{
if (finished)
{
zoomView.RemoveFromSuperview();
}
}
);
One more piece of the puzzle. When you're animating constraints, you can set the new constraint constants outside of an animation block and then call layoutIfNeeded inside the animation.
With view alphas, these need to be set directly inside the animation block.
Change this:
//setup position changes
myConstraint.constant = 10
myOtherConstraint.constant = 10
//whoops, alpha animates immediately
view.alpha = 0.5
UIView.animate(withDuration: 0.25) {
//views positions are animating, but alpha is not
self.view.layoutIfNeeded()
}
to
//setup position changes
myConstraint.constant = 10
myOtherConstraint.constant = 10
UIView.animate(withDuration: 0.25) {
view.alpha = 0.5
self.view.layoutIfNeeded()
}

iOS - Animation effects - Image pop-in

I'd like to have an image in my iphone app "pop-in" on screen rather than just appearing. By "pop-in" I mean that it would grow from a small dot to its actual size. For reference, this is exactly the same as the "pop" animation effect in Keynote.
I'm completely new to iOS animations, so if someone could point me in the direction on the animation effects I would need to use, it would be greatly appreciated.
Thanks
Brian
UPDATE
I've added this code from the suggestions below. This works but it scales my image down, rather than up. I know that is because I have 0.01 as the transform scale size, but I would like to know how I can start out with an image of size 0.0 and scale up to 1. Is it just a matter to setting the size of my image to 0?
Thanks
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration: 0.2];
image.transform = CGAffineTransformMakeScale(0.01, 0.01);
[UIView setAnimationDelegate:self];
[UIView commitAnimations];
The effect you’re looking for is something like this:
// instantaneously make the image view small (scaled to 1% of its actual size)
view.transform = CGAffineTransformMakeScale(0.01, 0.01);
[UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
// animate it to the identity transform (100% scale)
view.transform = CGAffineTransformIdentity;
} completion:^(BOOL finished){
// if you want to do something once the animation finishes, put it here
}];
if you want something like Facebook does on liking any post then use this
-(void)animateButton:(UIButton *)sender{
UIButton * btn = (UIButton *)sender;
[UIView animateWithDuration:0.3/1.5 animations:^{
btn.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1.4, 1.4); // scales up the view of button
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.3/2 animations:^{
btn.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.7, 0.7);// scales down the view of button
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.3/2 animations:^{
btn.transform = CGAffineTransformIdentity; // at the end sets the original identity of the button
}];
}];
}];}
just call this method when you want to animate the view
if you have text and image on the button and you just want to animate the image of the button then just replace "btn" with "btn.imageView" , this will just produce animation on the image view property of the button.
Hope it helps
All the best.
You have to animate the frame of the view, to shrink it from zero to the final state.
This can be done for example with UIView block animation.
So for example start with your view as an IBOutlet property self.myView with the final size and position, but set the hidden flag.
Then when you want it to appear use the following:
// Save old frame as final stater and set it to zero size for the start of the animation
// But keep the same center position, so it just grows and don't move around
CGRect oldFrame = self.myView.frame;
CGRect oldCenter = self.myView.center;
self.myView.frame = CGRectZero;
self.myView.center = oldCenter;
self.myView.hidden = NO;
NSTimeInterval duration = 0.3;
[UIView animateWithDuration:duration delay:0.0 options:UIViewAnimationOptionAllowUserInteraction animations:^{
// New position and size after the animation should be the same as in Interface Builder
self.myView.frame = oldFrame
}
completion:^(BOOL finished){
// You can do some stuff here after the animation finished
}];
Swift 2.0 version
view.transform = CGAffineTransformMakeScale(0.01, 0.01);
UIView.animateWithDuration(0.2, delay: 0, options: .CurveEaseOut, animations: { () -> Void in
// animate it to the identity transform (100% scale)
self.view.transform = CGAffineTransformIdentity;
}) { (finished) -> Void in
// if you want to do something once the animation finishes, put it here
}
For that you will have to use a simple UIView
Add the UIview to your current view.
- (void) initPopUpView
{
popup.alpha = 0;
popup.frame = CGRectMake (160, 240, 0, 0);
[self.view addSubview:popup];
}
- (void) animatePopUpShow
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];
[UIView setAnimationDelegate:self];
[UIView setAnimationWillStartSelector:#selector(initPopUpView)];
popup.alpha = 1;
popup.frame = CGRectMake (20, 40, 300, 400);
[UIView commitAnimations];
}

How to cancel UIView block-based animation?

I've searched loads of SO stuff and in Apple's references, but still unable to manage my problem.
What I have:
A screen with 2 UIImageViews and 2 UIButtons connected to them
2 kinds of animation:
Scaling up and then down of each image, one after another, only once in viewDidLoad
When a button pressed (a custom button hidden 'inside' of each UIImageView) it triggers animation of appropriate UIImageView–only one, not both–(also scale up, then down).
As I am writing for iOS4+ I'm told to use block based animations!
What I need:
How do I cancel a running animation? I've managed to cancel after all but the last one... :/
Here is my code snippet:
[UIImageView animateWithDuration:2.0
delay:0.1
options:UIViewAnimationOptionAllowUserInteraction
animations:^{
isAnimating = YES;
self.bigLetter.transform = CGAffineTransformScale(self.bigLetter.transform, 2.0, 2.0);
} completion:^(BOOL finished){
if(! finished) return;
[UIImageView animateWithDuration:2.0
delay:0.0
options:UIViewAnimationOptionAllowUserInteraction
animations:^{
self.bigLetter.transform = CGAffineTransformScale(self.bigLetter.transform, 0.5, 0.5);
} completion:^(BOOL finished){
if(! finished) return;
[UIImageView animateWithDuration:2.0
delay:0.0
options:UIViewAnimationOptionAllowUserInteraction
animations:^{
self.smallLetter.transform = CGAffineTransformScale(self.smallLetter.transform, 2.0, 2.0);
} completion:^(BOOL finished){
if(! finished) return;
[UIImageView animateWithDuration:2.0
delay:0.0
options:UIViewAnimationOptionAllowUserInteraction
animations:^{
self.smallLetter.transform = CGAffineTransformScale(self.smallLetter.transform, 0.5, 0.5);
}
completion:^(BOOL finished){
if (!finished) return;
//block letter buttons
[self.bigLetterButton setUserInteractionEnabled:YES];
[self.smallLetterButton setUserInteractionEnabled:YES];
//NSLog(#"vieDidLoad animations finished");
}];
}];
}];
}];
Somehow the smallLetter UIImageView is not working properly, because when pressed (through button) bigLetter is canceling animations properly...
EDIT:
I've used this solution, but still having problem with scaling down smallLetter UIImageView - not cancelling at all...
solution
EDIT2: I've added this at the beginning of next/prev methods:
- (void)stopAnimation:(UIImageView*)source {
[UIView animateWithDuration:0.01
delay:0.0
options:(UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionAllowUserInteraction)
animations:^ {
source.transform = CGAffineTransformIdentity;
}
completion:NULL
];
}
problem stays... :/ no idea how to interrupt last animation for letters in animation chain
You can stop all animations on a view by calling:
[view.layer removeAllAnimations];
(You'll need to import the QuartzCore framework to call methods on view.layer).
If you want to stop a specific animation, not all animations, your best best bet is to use CAAnimations explicitly rather than the UIView animation helper methods, then you will have more granular control and can stop animations explicitly by name.
The Apple Core Animation documentation can be found here:
https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CoreAnimation_guide/CreatingBasicAnimations/CreatingBasicAnimations.html
For iOS 10 use UIViewPropertyAnimator to animate.
It provides methods to start, stop and pause UIView animations.
let animator = UIViewPropertyAnimator(duration: 2.0, curve: .easeOut){
     self.view.alpha = 0.0
}
// Call this to start animation.
animator.startAnimation()
// Call this to stop animation.
animator.stopAnimation(true)
I'd add to Nick's answer that to make removeAllAnimations smooth next idea be very handy.
[view.layer removeAllAnimations];
[UIView transitionWithView:self.redView
duration:1.0f options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
[view.layer displayIfNeeded];
} completion:nil];
You can try this (in Swift):
UIView.setAnimationsEnabled(false)
UIView.setAnimationsEnabled(true)
Note: you can put code between those two calls if necessary, for example:
UIView.setAnimationsEnabled(false)
aview.layer.removeAllAnimations() // remove layer based animations e.g. aview.layer.opacity
UIView.setAnimationsEnabled(true)

Rotate a UIView on its X-axis(Horizontal axis)

I wanted to rotate a UIView on its horizontal axis for 360 degrees and then refresh the content in the view. I was looking out for solutions on this. Found a couple here n there. This is what I came out with.
[UIView animateWithDuration:1 delay:0 options:UIViewAnimationOptionTransitionNone animations:^{
self.tableView.layer.transform = CATransform3DMakeRotation(M_PI,1.0,0.0,0.0);
} completion:^(BOOL finished){
NSLog(#"Finished first pi");
[UIView animateWithDuration:1 delay:0 options:UIViewAnimationOptionTransitionNone animations:^{
self.tableView.layer.transform = CATransform3DMakeRotation(M_PI,1.0,0.0,0.0);
} completion:^(BOOL finished) {
NSLog(#"Finished second pi");
}];
}];
This flips the view but only by 180 degrees. I want it to flip one more time so that I can see the view normally..
Both my NSLogs are displayed one after the other. I am sure I am missing something here. ANy help would be helpful..
Thanks
In your completion block try concatenating the new transform with the current transform.
self.tableView.layer.transform = CATransform3DConcat(self.tableView.layer.transform, CATransform3DMakeRotation(M_PI,1.0,0.0,0.0));
You should check this answer How to make a CATransform3dMakeRotation rotate the other way? And chain together
I think that your problem is related with: "When you are working with a transform directly, Core Animation will interpolate the transform from the current value to the specified transform. It will find the shortest path to get to that transform, which will restrict the animation direction. If you try to animate the same transform property twice, the second value will simply override the first, not combine the two transforms together."
use this:-
rotatingView.layer.anchorPoint = CGPointMake(0.0f, 0.0f);
rotatingView.center = CGPointMake(0,
(rotatingView.center.y -
(rotatingView.bounds.size.height/2.0f)));
rotatingView.center = CGPointMake(0,
(rotatingView.center.y-
(rotatingView.bounds.size.height/2)));
// start the Page Open
[UIView beginAnimations:#"Animation" context:nil];
[UIView setAnimationDuration:13.0];
// set angle as per requirement
[rotatingView.layer setValue:[NSNumber numberWithInt:280]
forKeyPath:#"transform.rotation.x"];
[UIView commitAnimations];
You just have to change your code from 1.0 to 0.0 inside completion block and woohoo all done.
[UIView animateWithDuration:1 delay:0 options:UIViewAnimationOptionTransitionNone animations:^{
self.tableView.layer.transform = CATransform3DMakeRotation(M_PI,1.0,0.0,0.0);
} completion:^(BOOL finished){
NSLog(#"Finished first pi");
[UIView animateWithDuration:1 delay:0 options:UIViewAnimationOptionTransitionNone animations:^{
self.tableView.layer.transform = CATransform3DMakeRotation(M_PI,0.0,0.0,0.0);
} completion:^(BOOL finished) {
NSLog(#"Finished second pi");
}];
}];
You can also approach this using the .Repeat and .Autoreverse animation options + setting animation's repeat count. Here's an example in Swift:
UIView.animateWithDuration(time, delay: 0, options: [.Repeat, .Autoreverse], animations: {
UIView.setAnimationRepeatCount(3)
self.view.layer.transform = CATransform3DMakeRotation(CGFloat(M_PI), 1, 0, 0)
}) { (completed) in
// completion
}