I've got a UILabel that slides in and out of view, but after it slides back in it disappears. I want it to persist.
How can I achieve this? Also, why does this happen?
Here's the code:
[UIView animateWithDuration:0.1
delay:0.0
options:UIViewAnimationOptionAutoreverse
animations:^{
[self.listLabel setFrame:CGRectMake(325, 141, 320, 181)];
}
completion:nil];
Thanks.
In official documentation
UIViewAnimationOptionAutoreverse
Run the animation backwards and forwards. Must be combined with the UIViewAnimationOptionRepeat option.
Why don't you use UIViewAnimationOptionCurveEaseOut and UIViewAnimationOptionCurveEaseIn animation option for your label?
Just set your label's frame.origin.x = [outside the right side of it's superview's bound]
and set it back to it's original position when you want to slide-In again using EasyOut animation.
Here's something what I'm talking about...
CFRect frame = self.listLabel.frame;
//Point to hide your label by sliding it outside the right side of it's parent's view.
// mask or clipToBounds of parent's view must be YES
frame.origin.x = [self.listLabel.superview.frame.size.width];
[UIView animateWithDuration:0.1
delay:0.0
options:UIViewAnimationOptionCurveEaseIn
animations:^{
[self.listLabel setFrame:frame];
}
completion:nil];
And When you want to slide back in, use opposite animation and label's original position, of course you need to store it's original position somewhere so you could slide-in it back.
[UIView animateWithDuration:0.1
delay:0.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
[self.listLabel setFrame:label_original_frame];
}
completion:nil];
UIViewAnimationOptionAutoreverse is designed for a cyclical animation. To just bounce something offscreen and back, you should just write it as 2 animations:
CGRect originalFrame = self.listLabel.frame;
[UIView animateWithDuration:0.05
delay:0.0
options:UIViewAnimationOptionLayoutSubviews
animations:^{
[self.listLabel setFrame:CGRectMake(325, 141, 320, 181)];
}
completion:^(BOOL finished){
[UIView animateWithDuration:0.05
delay:0.0
options:UIViewAnimationOptionLayoutSubviews
animations:^{
[self.listLabel setFrame:originalFrame];
}
completion:nil];
}
];
As there still seems to be no valid answer, I propose a (now possible) approach:
In Xcode 6, with the app running in the simulator, go to "Debug" in the top bar, select "View Debugging" and "Capture View Hierarchy". Then go and search your missing Label. You can also see properties etc. of the Label in the right Xcode bar.
Related
I have an app in which I use a lot of animations with ease in/out curves. I use this function in all cases: UIView animateWithDuration:delay:options:animations:completion
All these animations are working ok, but now I am trying to add one to a drawer that pops in and out, and for some reason this particular animation is always linear:
[UIView animateWithDuration:2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
self.activityBar.view.frame = CGRectMake(0, self.activityBar.view.frame.origin.y, self.activityBar.view.frame.size.width, 20);
} completion:nil];
Why is this animation linear, while other animations with the same option are curved?
This is the view hierarchy for self.activityBar.view
-UIViewController
-UIViewController
-UIViewController (animation code lives here)
-UIViewController (activityBar)
-UIView (activityBar.view)
//Set old Frame for activityBar Here
[UIView animateWithDuration:2.0 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{
[self.view layoutIfNeeded];
//Update to the new frame
self.activityBar.view.frame = CGRectMake(0, self.activityBar.view.frame.origin.y, self.activityBar.view.frame.size.width, 20);
} completion:^(BOOL finished) {
}];
I have set the animation like seen in below image. In which UIbutton move from left to right and then top to bottom. Animation work correctly but after completion of animation UIButton comes to its original place before the segue perform. so, it's not look good. I want to set that after the completion of animation UIButton can't come to it's own place before segue .
Here is my try with Image.
//Move button Left to Right
- (IBAction)btnEasy:(id)sender {
Easy=YES;
NSLog(#"your x is: %f ", self.btnEasy.frame.origin.x);
NSLog(#"your y is: %f ", self.btnEasy.frame.origin.y);
x1=self.btnEasy.frame.origin.x;
y1=self.btnEasy.frame.origin.y;
CGRect screenRect = [[UIScreen mainScreen] bounds];
[UIView animateWithDuration:1.150 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
self.btnEasy.frame = CGRectMake(screenRect.size.width/1.80, self.btnEasy.frame.origin.y, self.btnEasy.frame.size.width, self.btnEasy.frame.size.height);
[self performSelector:#selector(btneasyanimation) withObject:self afterDelay:1.160 ];}
completion:^(BOOL finished) {
}];
//Move Button top to Bottom
if (Easy==YES) {
if (isiPad2 || isiPadAir || isiPadRatina) {
//[self.view layoutIfNeeded];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:1.0];
[_btnEasy setFrame:CGRectMake(self.view.frame.origin.x+290, self.view.frame.origin.y+900, self.btnEasy.frame.size.width, self.btnEasy.frame.size.height)];
[UIView commitAnimations];
}
else if (isiPhone4s) {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:1.0];
[_btnEasy setFrame:CGRectMake(self.view.frame.origin.x+92, self.view.frame.origin.y+428, self.btnEasy.frame.size.width, self.btnEasy.frame.size.height)];
[UIView commitAnimations];
}
}
[self performSelector:#selector(segueeMethod) withObject:self afterDelay:1.160 ];
Image :-
If you are not placing directly the button given it the frame, thus using autolayout (autoresize will end with the same effect). You need to explicitly use autolayout, retain a reference to your constraints and update them (you can search here how to do that) and then set the UIView animation block [button layoutIfNeeded]
You can see a detailed answer about it in this answer
There is an easy and quick way that will work with your current implementation. Provided you know exactly where you want the view to be once the animation is done, you can do the following:
in UIView animateWithDuration: ... assign the final transform (position & orientation) of the view in the completion block, i.e.:
completion:^(BOOL finished) {
// Assign views transform and appearance here, for when the animation completes
}
Hope that helps.
I have this code to simulate a multiple camera flash
[UIView animateWithDuration:0.1
delay:0.f
options:UIViewAnimationOptionAutoreverse
animations:^{
[UIView setAnimationRepeatCount:2];
flash.alpha=1.f;
}
completion:^(BOOL finished) {
flash.alpha = 0;
}];
flash is a white UIImageView (full screen) that starts with alpha = 0.
If you try to use this code, you will notice that at the end flash remains full white for a little time and it's not perfect for my effects, what can I do to solve this?
The problem with your code is you do autoreverse using the option UIViewAnimationOptionAutoreverse, while also specifying your own final state in the completion block.
Try this:
[UIView animateWithDuration:0.1f
delay:0
options:UIViewAnimationOptionAutoreverse
animations:^{
[UIView setAnimationRepeatCount:2];
flash.alpha=1.f;
}
completion:nil];
Hi I have piece of code which only one line is not working...
[UIView animateWithDuration:0.3 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{
[label setFrame:CGRectMake(0, 0, frame.size.width, kStandardLabelHeight)]; //working
[self.currentLabel setFrame:CGRectOffset(self.currentLabel.frame, frame.size.width, 0)]; //not working
[self.currentLabel setAlpha:0.0f]; //working
} completion:^(BOOL finished) {
[self.currentLabel removeFromSuperview];
self.currentLabel = label;
}];
I'm running out of ideas what is wrong...
What I find out is: if I turn off "Use Auto Layout", then it magically working, so this issue is connected with auto layout.
After a search, I find this: http://weblog.invasivecode.com/post/42362079291/auto-layout-and-core-animation-auto-layout-was
Add constraint outlet mapping for your view, then instead of using setFrame, updating constraints will do the trick!
Below is my final implementation (_topConstraint is the top vertical space constraint of table view):
- (IBAction)switchButtonTouched:(id)sender
{
if (_topConstraint.constant <= 0)
_topConstraint.constant = _buttonView.frame.size.height;
else
_topConstraint.constant = 0;
[_tableView setNeedsUpdateConstraints];
[UIView animateWithDuration:0.5f animations:^(void){
[_tableView layoutIfNeeded];
} completion:^(BOOL finished){
}];
}
Frame must be a CGRect with 4 parameters: (xPosition,yPosition,width,height). Use CGRectMake for set frame
self.currentLabel.frame = CGRectMake(100, 100, self.currentLabel.frame.size.width, self.currentLabel.frame.size.height)
You set 0.3 sec the animation duration, and when it s end you remove it from the view. This is too short. set the duration for example 2, and you will see that your label is moving .
Sometimes you should set frames for animating views also after animation, for example in completion block, try something like that
[UIView animateWithDuration:0.3 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{
[label setFrame:CGRectMake(0, 0, frame.size.width, kStandardLabelHeight)]; //working
[self.currentLabel setFrame:CGRectOffset(self.currentLabel.frame, frame.size.width, 0)]; //not working
[self.currentLabel setAlpha:0.0f]; //working
} completion:^(BOOL finished) {
self.frame = currentLabelFrame;
label.frame = label.frame;
[self.currentLabel removeFromSuperview];
self.currentLabel = label;
}];
If your issue is neither Autolayout related, or the others listed here, there is also another possible problem that turned out to be my issue. I'm simultaneously running a UIView transition (transitionFromView:toView:) on views that take up the same screen space (Different superviews, not related, other than positioning in the superview of the overarching view controller).
My code looked like this:
[UIView transitionFromView:self.someView
toView:self.someOtherView
duration:0.6f
options:UIViewAnimationOptionTransitionCrossDissolve | UIViewAnimationOptionShowHideTransitionViews
completion:NULL];
[UIView animateWithDuration:0.3
delay:0.0 options:UIViewAnimationOptionCurveEaseOut
animations:^{
[self.someThirdView setFrame:someFrame]; //not working
[self.someThirdView setAlpha:1.0f]; //working
} completion:nil];
The frame changed, but it popped to the new frame rather than animating. I'm guessing this is an internal iOS issue. As soon as I removed the "transitionFromView:..." call, the frame animation worked fine.
My solution for now has been to move the second animation into the completion block of the transitionFromView. It's not perfect, as the two animations should have lined up, but it is a passable solution for now.
Apple's documentation describes UIViewAnimationOptionLayoutSubviews as:
Lay out subviews at commit time so that they are animated along with
their parent.
Here is a sample of the code I'm interested in. I wish to animate the -layoutSubviews of detailView; however, it doesn't seem to layout the subviews of detailView, so I'm not sure what effect it actually has.
void (^animation) () = ^
{
[self.detailView setNeedsLayout];
[self.detailView layoutIfNeeded];
};
[UIView animateWithDuration:0.5
delay:0.0
options:UIViewAnimationOptionLayoutSubviews
animations:^{
animation();
}
completion:nil];
Since you want your second animation to occurs from the current state of your first animation (whether it is finished or not) I recommend to use the UIViewAnimationOptionLayoutSubviews option when setting your second animation.
[UIView animateWithDuration:0.2
delay:0.0
options:UIViewAnimationOptionLayoutSubviews
animations:^{
CGAffineTransform settingsTransform = CGAffineTransformMakeTranslation(self.animatedView.frame.size.width, 0);
self.animatedView.transform = settingsTransform;
}
completion:nil];