Slide UILabel Onto View Controller - ios

I'm trying to move a UILabel from a starting position of off the top of my UIViewController in a smooth slide type animation so that it slides down from the top when the view loads and then stops at a y position for about 10 seconds. After 10 seconds I want to slide back off the view again.
-(void) animateInstructionLabel
{
float newX = 50.0f;
float newY = 100.0f;
[UIView transitionWithView:self.lblInstruction
duration:10.0f
options:UIViewAnimationCurveEaseInOut
animations:^(void) {
lblInstruction.center = CGPointMake(newX, newY);
}
completion:^(BOOL finished) {
// Do nothing
}];
}
But I don't know how to do the 10 second delay and then move back within the method above. The end result is that I want this to be a label that appears like a notification and then moves off screen again.
Could someone hep me put these pieces described above together?
EDIT
I am adding this based on answer below:
-(void) animateInstructionLabel
{
float newX = lblInstruction.frame.origin.x;
float newY = 20.0f;
lblInstruction.center = CGPointMake(lblInstruction.frame.origin.x, -20.0f);
lblInstruction.bounds = CGRectMake(lblInstruction.frame.origin.x, -20.0f, 650.0f, 40.0f);
[UIView animateWithDuration:3.0f
delay:0
options:UIViewAnimationCurveEaseInOut
animations:^(void) {
lblInstruction.center = CGPointMake(newX, newY);
}
completion:^(BOOL finished) {
[UIView animateWithDuration:5.0f
delay:5.0
options:UIViewAnimationCurveEaseInOut
animations:^(void) {
lblInstruction.center = CGPointMake(newX, -20);
}
completion:^(BOOL finished) {
// Do nothing
}
];
}
];
}
But even though I am setting the label.center off the screen before the animation starts I am seeing that it moves from top left corner of the viewcontroller to the center of the viewcontroller. It is not keeping the x position that it should be set to before the animation begins.

Try adding this after your animation block (oldX,oldY are the old coordinates, before animating the label in):
double delayInSeconds = 10.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[UIView transitionWithView:self.lblInstruction
duration:10.0f
options:UIViewAnimationCurveEaseInOut
animations:^(void) {
lblInstruction.center = CGPointMake(oldX, oldY);
}
completion:^(BOOL finished) {
// Do nothing
}];
});

Something like this should work:
-(void) animateInstructionLabel {
float newX = 50.0f;
float newY = 100.0f;
labelInstruction.center = CGPointMake(newX, -20); // start off screen
[UIView animateWithDuration:10.0f
delay:0
options:UIViewAnimationCurveEaseInOut
animations:^(void) {
lblInstruction.center = CGPointMake(newX, newY);
}
completion:^(BOOL finished) {
[UIView animateWithDuration:10.0f
delay:10.0
options:UIViewAnimationCurveEaseInOut
animations:^(void) {
lblInstruction.center = CGPointMake(newX, -20);
}
completion:^(BOOL finished) {
// Do nothing
}
];
}
];
}

Here is what worked in case it helps somebody else. I had to use .frame instead of .center to set the initial position and then the subsequent animation back to that position.
-(void) animateInstructionLabel
{
lblInstruction.frame = CGRectMake(lblInstruction.frame.origin.x, -40.0f, 650.0f, 40.0f);
[self.view addSubview:lblInstruction];
lblInstruction.hidden = NO;
float newX = lblInstruction.frame.origin.x;
float newY = 20.0f;
[UIView animateWithDuration:3.0f
delay:0
options:UIViewAnimationCurveEaseInOut
animations:^(void) {
lblInstruction.center = CGPointMake(newX, newY);
}
completion:^(BOOL finished) {
[UIView animateWithDuration:3.0f
delay:5.0
options:UIViewAnimationCurveEaseInOut
animations:^(void) {
lblInstruction.frame = CGRectMake(lblInstruction.frame.origin.x, -40.0f, 650.0f, 40.0f);
}
completion:^(BOOL finished) {
lblInstruction.hidden = YES;
}
];
}
];
}
This smoothly makes the label slide down from off the view, stop for 5 seconds and then smoothly moves it back vertically off the view.
Thanks for the previous answers which lead me to the above final solution.

Related

Objective-c animation with constraints instability issue for trailing constraint

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;
}

Animation works on iphone but not on ipad

I'm using this code to animate buttons to bounce with different delays:
- (void) animateWithDuration: (float) duration andObject: (UIButton *) buttonToAnimate{
buttonToAnimate.hidden = YES;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, duration * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[self animateButton: buttonToAnimate];
});
}
- (void) animateButtons
{
[self animateWithDuration:0.3 andObject:self.photoAlbum];
[self animateWithDuration:0.7 andObject:self.camera];
[self animateWithDuration: 0.45 andObject:self.helpInfo];
}
- (void) animateButton: (UIButton *) button
{
button.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.001, 0.001);
button.hidden = NO;
[UIView animateWithDuration:0.3/0.7 animations:^{
button.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1.1, 1.1);
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.3/1.0 animations:^{
button.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.9, 0.9);
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.3/1.0 animations:^{
button.transform = CGAffineTransformIdentity;
}];
}];
}];
}
It works perfectly on iphone, but on ipad (simulator) the buttons makes a little jump up to the left with about 20 points on the completion block. Then back 20 point on the second completion. Using option: UIViewAnimationOptionTransitionNone (or any of the options) on the animation lessens the jump a tiny bit but you can still see it. Any idea whats wrong?

Animation of UIButton decreases its size

Here is a small clip of a view being animated by me:
Animation flash
I am having problems when animation from ? to S and vice versa. I am setting the appropriate frames to go off screen, and then back on from the other size. Why does the size of the black button decrease with every move around it?
-(void)moveToRight
{
//just made this method up, but my actual code
//special case
if (currentDay == 7) {
//move off the screen to the right
CGRect offScreenRightFrame = CGRectMake(self.circle.frame.origin.x + 60, self.circle.frame.origin.y, self.circle.frame.size.width, self.circle.frame.size.height);
//move to the left of the screen so we can animate it in
CGRect offScreenLeftFrame = CGRectMake(-40, self.circle.frame.origin.y, self.circle.frame.size.width, self.circle.frame.size.height);
if (self.delegate) {
if ([self.delegate respondsToSelector:#selector(dayChangedTo:)]) [self.delegate dayChangedTo:[self getCurrentDay]];
}
[self pulseCircle];
[UIView animateWithDuration:0.25f delay:0.0f options:UIViewAnimationOptionCurveLinear animations:^{
self.circle.frame = offScreenRightFrame;
}completion:^(BOOL finished) {
if (finished) {
self.circle.alpha = 0.0f;
self.circle.frame = offScreenLeftFrame;
[UIView animateWithDuration:0.25f delay:0.0f options:UIViewAnimationOptionCurveLinear animations:^{
self.circle.center = self.labelSun.center;
self.circle.alpha = 1.0f;
}completion:^(BOOL finished) {
if (finished) {
[UIView animateWithDuration:0.25f animations:^{
[self changeColors];
[self pulseCircle];
}];
}
}];
}
}];
}
-(void)moveLeft
{
if (currentDay == 8) {
CGRect circleFrame = self.circle.frame;
CGRect offScreenLeft = CGRectOffset(circleFrame, -20, 0);
CGRect offScreenRightFrame = CGRectMake(self.labelQuestion.frame.origin.x + 30, self.labelQuestion.frame.origin.y, circleFrame.size.width, circleFrame.size.height);
[self pulseCircle];
[UIView animateWithDuration:0.25f delay:0.0f options:UIViewAnimationOptionCurveLinear animations:^{
self.circle.frame = frame;
}completion:^(BOOL finished) {
if (finished) {
self.circle.alpha = 0.0f;
self.circle.frame = frameFinal;
[UIView animateWithDuration:0.25f delay:0.0f options:UIViewAnimationOptionCurveLinear animations:^{
self.circle.center = self.labelQuestion.center;
self.circle.alpha = 1.0f;
}completion:^(BOOL finished) {
if (finished) {
[UIView animateWithDuration:0.25f animations:^{
[self changeColors];
[self pulseCircle];
}];
}
}];
}
}];
}
- (void)pulseCircle
{
__block UILabel *day = [self getLabelOfDay];
[UIView animateWithDuration:TRANLATE_DURATION/2 delay:0.0f options:UIViewAnimationOptionBeginFromCurrentState animations:^{
self.circle.layer.transform = CATransform3DMakeScale(1.35f, 1.35f, 1);
day.transform = CGAffineTransformMakeScale(1.35f, 1.35f);
}completion:^(BOOL finished) {
[UIView animateWithDuration:TRANLATE_DURATION/2 animations:^{
self.circle.layer.transform = CATransform3DIdentity;
day.transform = CGAffineTransformIdentity;
}];
}];
}
I just put my logic.. honestly i don't read/see your code/logic but may be my idea work for you ;)
So, I think.. you should add size of circle in public variable as default size. And set this size whenever you rich at.
if (currentDay == 0 || currentDay == 8)
{
// Here you need to set your default size.
}
May be my logic work for you, Because 1 to 7 day its work fine but issue created at when currentDay rich at 0 or 8 day.
Thanks :)

UIView animation: simulating velocity

I am trying to use a UIView animation to simply move a view onto the screen:
[UIView animateWithDuration:.10 delay:0 options: nil animations:^
{
self.menusView.frame = endingMenuViewFrame;;
}
completion:^(BOOL finished)
{
}];
I'm wanting to add an animation so that UIView floats a little when it reaches the top before it comes down, i.e. akin to if someone jumps in the air - when they first jump, they shoot up quickly, but then gravity gradually slows them down as they reach the top of their jump, and eventually it pushes them back to earth. Does anyone know how to accomplish this?
Try with this code. This will make your view bounce three times with each time your height reduced by half. You may add more bounces.
CGFloat offset = 200.0;
CGRect originalFrame = self.menusView.frame;
[UIView animateWithDuration:1.0 animations:^{
CGRect frame = self.runnerAlertView.frame;
frame.origin.y = frame.origin.y - offset;
self.menusView.frame = frame;
} completion:^(BOOL finished){
[UIView animateWithDuration:1.0 animations:^{
self.menusView.frame = originalFrame;
} completion:^(BOOL finished) {
[UIView animateWithDuration:1.0 animations:^{
CGRect frame = self.menusView.frame;
frame.origin.y = frame.origin.y - 0.5 *offset;
self.menusView.frame = frame;
} completion:^(BOOL finished){
[UIView animateWithDuration:1.0 animations:^{
self.menusView.frame = originalFrame;
} completion:^(BOOL finished) {
[UIView animateWithDuration:1.0 animations:^{
CGRect frame = self.runnerAlertView.frame;
frame.origin.y = frame.origin.y - 0.25 * offset;
self.menusView.frame = frame;
} completion:^(BOOL finished){
[UIView animateWithDuration:1.0 animations:^{
self.menusView.frame = originalFrame;
}];
}];
}];
}];
}];
}];

My animatewithduration, completion block is performed only once

I use the following block of code to slide a UIView down and when finished rotate another UIView.
The second part of the animation, the completion block is only performed once which means the 1st animation is not completed else it would reach the completion block.
On the iphone simulator it looks as if the 1st animation did finish...
can anyone help me figure this out?
my NSLog says:
finished 1st
started 2nd
finished 1st
finished 1st
finished 1st
.
.
.
- (IBAction) move
{
[UIView animateWithDuration:0.7 animations:^{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.7];
[UIView setAnimationRepeatCount:1];
[UIView setAnimationRepeatAutoreverses:NO];
CGPoint pos = movingtTable.center;
float moveDistance = 220.0;
if(!isViewVisible){
//expose the view
pos.y = pos.y+moveDistance;
//disable selection for xy table
xTable.userInteractionEnabled = NO;
yTable.userInteractionEnabled = NO;
//angle = M_PI;
}
else
{
pos.y = pos.y-moveDistance;
xTable.userInteractionEnabled = YES;
yTable.userInteractionEnabled = YES;
//angle = -M_PI;
}
isViewVisible = !isViewVisible;
movingtTable.center = pos;
NSLog(#"finished 1st");
}completion:^(BOOL finished){
NSLog(#"started 2nd");
[UIView animateWithDuration:0.4 animations:^{
//[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.4];
//[UIView setAnimationRepeatCount:1];
//[UIView setAnimationRepeatAutoreverses:NO];
arrows.transform = CGAffineTransformMakeRotation(angle);
}completion:^(BOOL finished){
angle = -angle;
}];
}];
Why are you trying to initialize another UIView animation inside the animateWithDuration block code? Update your code to the following and make sure you're not performing multiple animations of a single view at a time.
- (IBAction) move
{
[UIView animateWithDuration:0.7 animations:^{
CGPoint pos = movingtTable.center;
float moveDistance = 220.0;
if(!isViewVisible){
//expose the view
pos.y = pos.y+moveDistance;
//disable selection for xy table
xTable.userInteractionEnabled = NO;
yTable.userInteractionEnabled = NO;
//angle = M_PI;
}
else
{
pos.y = pos.y-moveDistance;
xTable.userInteractionEnabled = YES;
yTable.userInteractionEnabled = YES;
//angle = -M_PI;
}
isViewVisible = !isViewVisible;
movingtTable.center = pos;
NSLog(#"finished 1st");
}
completion:^(BOOL finished){
NSLog(#"started 2nd");
[UIView animateWithDuration:0.4 animations:^{
arrows.transform = CGAffineTransformMakeRotation(angle);
}completion:^(BOOL finished){
angle = -angle;
}];
}];
BTW: The block code requires some serious refactoring, if you ask me :)
You are mixing and matching paradigms and I believe that is causing the issue you are seeing. You are creating an animation block, but inside of that block you are creating a new animation routine with the 'old' paradigm for running UIView animations. Apple is leading people away from the old paradigm and I would encourage you to ONLY use blocks as well.
This is why the completion block only runs once, the UIView animateWith block code only runs once. However, your internal animation code runs multiple times.
Take out:
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.7];
[UIView setAnimationRepeatCount:1];
[UIView setAnimationRepeatAutoreverses:NO];
If you want your animation block to run several times, then use the full method:
animateWithDuration:delay:options:animations:completion:
Make the delay = 0, and set your options to UIViewAnimationOptionRepeat, or whatever you need to accomplish the number of cycles you want the block to complete.
Here is my suggestion assuming you want it to repeat:
- (IBAction) move
{
[UIView animateWithDuration:0.7
delay:0
options:UIViewAnimationOptionRepeat
animations:^{
CGPoint pos = movingtTable.center;
float moveDistance = 220.0;
if(!isViewVisible) {
//expose the view
pos.y = pos.y+moveDistance;
//disable selection for xy table
xTable.userInteractionEnabled = NO;
yTable.userInteractionEnabled = NO;
//angle = M_PI;
}
else {
pos.y = pos.y-moveDistance;
xTable.userInteractionEnabled = YES;
yTable.userInteractionEnabled = YES;
//angle = -M_PI;
}
isViewVisible = !isViewVisible;
movingtTable.center = pos;
NSLog(#"finished 1st");
}
completion:^(BOOL finished){
NSLog(#"started 2nd");
[UIView animateWithDuration:0.4
animations:^{
arrows.transform = CGAffineTransformMakeRotation(angle);
}
completion:^(BOOL finished){
angle = -angle;
}];
}];
}

Resources