Keep the End Position of Animation - objective-c

I tried everything, but everytime its the same problem:
i want to move a button for y = 276. when the animation ends, my buttons jumps back to the startposition, but i want that the endanimationposition is the new position, and the button has to stay there, until a new animation is called.
tried with
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1];
CGPoint p = _cell00.center;
p.x += 100;
_cell00.center = p;
[UIView commitAnimations];
[UIView beginAnimations:nil context:nil];
same issue like
[UIView animateWithDuration:1.0 animations:^{
_cell00.frame = CGRectOffset(_cell00.frame, 0, 20);
}];
or
[UIView animateWithDuration:0.5 animations:^{
_cell00.center = CGPointMake(0, 20.0);
}];
EDIT:
I call this Animation with my Button called statisticsBUttonPressed.
- (IBAction)statisticsButtonPressed:(id)sender {
if (statOrGame == 0) {
statOrGame = 1;
}else {
statOrGame = 0;
}
NSLog(#"statOrGame? %d", statOrGame);
[self animateView:(UIButton *)sender];
}
-(void) animateView:(UIButton *)sender {
sender.userInteractionEnabled = NO;
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone)
{ // The iOS device = iPhone or iPod Touch
NSLog(#"IS IPHONE 5");
CGSize iOSDeviceScreenSize = [[UIScreen mainScreen] bounds].size;
if (iOSDeviceScreenSize.height == 568)
{
if (statOrGame) {
[UIView animateWithDuration:1.0 animations:^{
_cell00.frame = CGRectOffset(_cell00.frame, 0, 20);
}];
}
}
}
}

The problem is that you're using auto layout. You can't (just) change the frame of a view that is positioned by auto layout, because what positions the view is its constraints. You need to change the constraints. You can do this at the end of the animation, or you can simply animate the change of constraints.

Related

Animate a UITextField when changing from hidden to visible using AutoLayout

I have a UITextField that is set to hidden, when I click the search button I want to make it visible but I want to create an animation like a slide-in, is it possible to recreate this effect if i'm using autoLayout?
The code I used for the animation is the current (it creates a fade-in effect):
if(!currentSrcState)
{
_searchField.hidden = NO;
[UIView animateWithDuration:0.3
delay:0.0
options:UIViewAnimationOptionTransitionCurlDown
animations:^ {
_searchField.alpha = 1.0;
}
completion:nil];
currentSrcState = YES;
}
else
{
[UIView animateWithDuration:0.3
delay:0.0
options:UIViewAnimationOptionTransitionCurlDown
animations:^ {
_searchField.alpha = 0;
}
completion:^(BOOL finished){
_searchField.hidden = YES;
}];
currentSrcState = NO;
}
What I want to acheive is that when the _searchField is hidden the constraint gets recalculated in order to move what is under the searchField up
Instead of set the button to hidden, set its alpha value to 0.0 before load the view. Then change your code to:
if(!currentSrcState)
{
[UIView animateWithDuration:0.3
delay:0.0
options:UIViewAnimationOptionTransitionCurlDown
animations:^ {
_searchField.alpha = 1.0;
}
completion:nil];
currentSrcState = YES;
}
else
{
[UIView animateWithDuration:0.3
delay:0.0
options:UIViewAnimationOptionTransitionCurlDown
animations:^ {
_searchField.alpha = 0.0;
}
completion:nil];
currentSrcState = NO;
}

How to fade in and fade out a label. continuously

In my Xcode project I have put a label on an xib.
I want to fade the label in and out continuously until the user taps the screen. When this happens I want a new view to appear.
Can anyone suggest how to do the fade-in/out?
Instead of nesting blocks and manually restarting your animations, you can use the option pair UIViewAnimationOptionAutoreverse | UIViewAnimationOptionRepeat to tell Core Animation you want the label to fade in and out continuously.
- (void)startAnimatingLabel
{
self.label.alpha = 0;
[UIView animateWithDuration:1
delay:0
options: UIViewAnimationOptionAutoreverse | UIViewAnimationOptionRepeat
animations:^{
self.label.alpha = 1;
} completion:nil];
}
To stop the animations from running, just remove them from the label's layer.
- (IBAction)tap:(UITapGestureRecognizer *)sender
{
[self.label.layer removeAllAnimations];
self.label.alpha = 0;
[self presentNewView];
}
EDIT: A less abrupt way to finish would be to animate from the current view state to the final one (this will interrupt the current, repeating animation).
- (IBAction)tap:(UITapGestureRecognizer *)sender
{
[UIView animateWithDuration:1
delay:0
options:UIViewAnimationOptionBeginFromCurrentState
animations:^{
self.label.alpha = 0;
} completion:^(BOOL finished){
[self presentNewView];
}];
}
You could put a pair of chained animation in a loop or call a function that holds the chained animation everytime until you encounter a user tap.
By Chained animation, I mean something like this (You can set the animation duration to suit your needs):
myLabel.alpha = 0.0;
[UIView animateWithDuration:1.0
delay:0.0
options: UIViewAnimationCurveEaseOut
animations:^{
myLabel.alpha = 1.0;
}
completion:^(BOOL finished){
[UIView animateWithDuration:1.0
delay:1.0
options: UIViewAnimationCurveEaseOut
animations:^{
myLabel.alpha = 0.0;
}
completion:^(BOOL finished){
NSLog(#"Done!");
}];
}];
The above code will first fade in your label and then fade it out. You can put that in a function and call it until you encounter user tap.
Create a CABasicAnimation and add it to your label:
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:#"opacity"];
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
animation.fromValue = #(1.0f);
animation.toValue = #(0.1f);
animation.repeatCount = INFINITY;
animation.duration = 0.75;
animation.autoreverses = YES;
[label.layer addAnimation:animation];
When you click on your button, just get a pointer to that label and remove all the animations:
[label.layer removeAllAnimations];
Try this it give you the ability to manage the animation repeat count if you replaced INFINITY with your repeat count
fadingLabel.alpha = 1.0;
[UIView beginAnimations:#"fadingLabel" context:nil];
[UIView setAnimationDuration:4.0];
[UIView setAnimationRepeatCount:INFINITY];
fadingLabel.alpha = 0.0;
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView commitAnimations];
Wayne Hartman's Answer in Swift 4
let animation = CABasicAnimation(keyPath: "opacity")
animation.fromValue = 1
animation.toValue = 0.1
animation.duration = 0.75
animation.repeatCount = .infinity
animation.autoreverses = true
label.layer.add(animation, forKey: nil)
and
label.layer.removeAllAnimations()

How to move view for keyboard in portrait orientations

I have an app that runs in portrait and portraitUpsideDown only. I need to push the view up when the keyboard appears and pull it back down when it disappears. The following code works perfectly if the device stays in portrait, but if it is in portraitUpsideDown the view moves the wrong direction (-260 instead of 260), plus if the orientation changes while the keyboard is showing, it's not handled... The keyboardWillHide method works fine in both orientations. Is there a way to move the view RELATIVE to the keyboard or status bar so it doesn't matter what orientation the device is in???
- (void) keyboardWillShow:(NSNotification *) notification
{
NSLog(#"Keyboard Will Show");
double animationDuration;
animationDuration = [[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
[UIView animateWithDuration:animationDuration delay:0 options:UIViewAnimationCurveEaseIn animations:^{
self.view.center = CGPointMake(self.view.center.x, self.view.center.y + -260);
}completion:^(BOOL finished){
}];
}
- (void) keyboardWillHide:(NSNotification *) notification
{
double animationDuration;
animationDuration = [[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
NSLog(#"Keyboard Will Hide");
[UIView animateWithDuration:animationDuration delay:0 options:UIViewAnimationCurveEaseIn animations:^{
[self.view setFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
}completion:^(BOOL finished){
}];
}
I solved it (less than elegantly) this way:
NOTE: Things you SHOULD do, and I will change this code to do them eventually are: create a property to hold the keyboard animation duration so I can use it outside of the keyboard delegate methods, and similarly create a property for the offset and determine it using the userInfo for the height of the keyboard.
- (void) keyboardWillShow:(NSNotification *) notification
{
NSLog(#"Keyboard Will Show");
if (self.interfaceOrientation == UIInterfaceOrientationPortrait)
offset = -260;
else
offset = 260;
double animationDuration;
animationDuration = [[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
[UIView animateWithDuration:animationDuration delay:0 options:UIViewAnimationCurveEaseIn animations:^{
self.view.center = CGPointMake(self.view.center.x, self.view.center.y + offset);
}completion:^(BOOL finished){
}];
}
- (void) keyboardWillHide:(NSNotification *) notification
{
double animationDuration;
animationDuration = [[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
NSLog(#"Keyboard Will Hide");
[UIView animateWithDuration:animationDuration delay:0 options:UIViewAnimationCurveEaseIn animations:^{
self.view.center = CGPointMake(self.view.center.x, self.view.center.y - offset);
}completion:^(BOOL finished){
}];
}
- (void) keyboardDidShow
{
NSLog(#"Keyboard Did Show");
keyboardIsShowing = YES;
}
- (void) keyboardDidHide
{
NSLog(#"Keyboard Did Hide");
keyboardIsShowing = NO;
}
-(void) willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
if (keyboardIsShowing && UIInterfaceOrientationIsPortrait(toInterfaceOrientation))
{
if (toInterfaceOrientation == UIInterfaceOrientationPortrait && offset == 260)
offset = -260;
else if (toInterfaceOrientation == UIInterfaceOrientationPortraitUpsideDown && offset == -260)
offset = 260;
else
return;
[UIView animateWithDuration:.25 delay:0 options:UIViewAnimationCurveEaseIn animations:^{
self.view.center = CGPointMake(self.view.center.x, self.view.center.y + 2* offset);
}completion:^(BOOL finished){
}];
}
}
Unfortunately you will have to manage this yourself. You can interrogate the current orientation and set your y-axis adjustment appropriately.
int movementDistance = -260;
if (UIInterfaceOrientationPortraitUpsideDown == [self interfaceOrientation]) movementDistance = -movementDistance;
You need to set the frame height, or set the contentInset for the view, not the center.

Checking if the UIPickerView is shown or hidden? The *if* conditions?

I have a little problem with my UIPickerView animation.
I did set up the animation so when I click a button the UIPickerView will slide up and after another click it will slide down. But I hit the problem on if. I tried to set up a new settings bool and set it's value after each animation, so the if was just checking for the bool. I'm not sure if I did explained it well, but maybe you get the idea from the code.
But unfortunately it's not working... Any ideas?
- (void)viewDidLoad
{
[super viewDidLoad];
settings = [NSUserDefaults standardUserDefaults];
[settings setBool:NO forKey:#"pickerShown"];
[settings synchronize];
}
- (IBAction)showPicker:(id)sender {
CGRect rect = countryPicker.frame;
CGPoint origin = CGPointMake(0, 510); // Some off-screen y-offset here.
rect.origin = origin;
countryPicker.frame = rect;
if ([settings boolForKey:#"pickerShown"] == YES) {
// Perform transform to slide it off the screen.
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
countryPicker.transform = CGAffineTransformMakeTranslation(0, -0); // Offset.
[UIView commitAnimations];
[settings setBool:NO forKey:#"pickerShown"];
[settings synchronize];
} else if ([settings boolForKey:#"pickerShown"] == NO) {
// Perform transform to slide it onto the screen.
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
countryPicker.transform = CGAffineTransformMakeTranslation(0, -266); // Offset.
[UIView commitAnimations];
[settings setBool:YES forKey:#"pickerShown"];
[settings synchronize];
}
}
EDIT:
Just found the solution...
If anyone's interested - here it is:
The h. file:
.
.
.
{
BOOL pickerShown;
}
.
.
.
The .m file:
- (void)viewDidLoad
{
[super viewDidLoad];
CGRect rect = countryPicker.frame;
CGPoint origin = CGPointMake(0, 510); // Some off-screen y-offset here.
rect.origin = origin;
countryPicker.frame = rect;
pickerShown = NO;
}
- (IBAction)showPicker:(id)sender {
if (pickerShown == NO) {
// Perform transform to slide it onto the screen.
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1];
//[UIView setAnimationDidStopSelector:#selector(hidePicker)];
countryPicker.transform = CGAffineTransformMakeTranslation(0, 0); // Offset.
[UIView commitAnimations];
[self performSelector:#selector(hidePicker) withObject:nil afterDelay:1];
} else if (pickerShown == YES) {
//countryPicker.hidden = NO;
// Perform transform to slide it onto the screen.
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1];
countryPicker.transform = CGAffineTransformMakeTranslation(0, -266); // Offset.
[UIView commitAnimations];
countryPicker.hidden = NO;
}
}
If a view is visible on screen, it's window property will be non-nil.
Just found the solution... If anyone's interested - here it is:
The h. file:
.
.
.
{
BOOL pickerShown;
}
.
.
.
The .m file:
- (void)viewDidLoad
{
[super viewDidLoad];
CGRect rect = countryPicker.frame;
CGPoint origin = CGPointMake(0, 510); // Some off-screen y-offset here.
rect.origin = origin;
countryPicker.frame = rect;
pickerShown = NO;
}
- (IBAction)showPicker:(id)sender {
if (pickerShown == NO) {
// Perform transform to slide it onto the screen.
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1];
//[UIView setAnimationDidStopSelector:#selector(hidePicker)];
countryPicker.transform = CGAffineTransformMakeTranslation(0, 0); // Offset.
[UIView commitAnimations];
[self performSelector:#selector(hidePicker) withObject:nil afterDelay:1];
} else if (pickerShown == YES) {
//countryPicker.hidden = NO;
// Perform transform to slide it onto the screen.
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1];
countryPicker.transform = CGAffineTransformMakeTranslation(0, -266); // Offset.
[UIView commitAnimations];
countryPicker.hidden = NO;
}
}
You can check it with:
self.countryPicker.superview
If picker is hidden then superview will be nil. Otherwise it will be containing view.
If all you want is the basic effect of displaying the picker view, then removing it again there is an easier way.
pseudocode:
//do any picker initialization here
if(!pickerIsShowing)
[self.view addSubview:yourPickerView];
else
[self.yourPickerView removeFromSuperView];

how to stop animation after using beginAnimations?

i use the following code to do a string rolling, but how to stop the animation?
[UIView beginAnimations:#"ruucc" context:NULL];
[UIView setAnimationDuration:12.8f];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
[UIView setAnimationDelegate:self];
[UIView setAnimationRepeatAutoreverses:NO];
[UIView setAnimationRepeatCount:999999];
frame = label1.frame;
frame.origin.x = -12;
label1.frame = frame;
[UIView commitAnimations];
- (void)doAnimation
{
[UIView animateWithDuration:12.8f
delay: 0.0
options: UIViewAnimationCurveLinear
animations:^{
frame = label1.frame;
frame.origin.x = -12;
label1.frame = frame;
}
completion:^(BOOL finished){
if(keepAnimating) {
[self doAnimation];
}
}];
}
In header:
BOOL keepAnimating;
To start animation:
keepAnimating = YES;
[self doAnimation];
To stop animation:
keepAnimating = NO;
This solution uses the block-based animation methods on UIView. Concerning the old set of animation methods ( [UIView beginAnimations] etc ) the UIView class reference states:
Use of the methods in this section is discouraged in iOS 4 and later. Use the block-based animation methods instead.