I would like to know if there is a way to change a label's frame's width (not the fontSize or something) with a smooth animation.
I already tried the following, that did (obviously) not work:
_myLabel.frame = CGRectMake(139,193,42,21);
[UIView animateWithDuration:1 animations:^ {
_myLabel.frame = CGRectMake(139, 193, 100, 21);
} completion:^(BOOL finished) {
}];
So what basically happened after running this code was that it changed the width as expected but without any animation.
Any ideas?
You can't change the frame size of labels...
You can reach correct animation behavior.. set label.contentMode = UIViewContentModeCenter but it looks ugly
But you can...:
change is the bounds, rather than the frame https://stackoverflow.com/a/3304220
add an UIView and then add UILabel as its subview and animate UIView https://stackoverflow.com/a/15639093 and https://stackoverflow.com/a/22224630
Use a CGAffineTransform to do this but have some ugly side effects like distorting the text on the label https://stackoverflow.com/a/13066366
change the font of UILabel with transform Animation Animating UILabel Font Size Change
Related
I have a small button in the top left of the screen and it is set in place with constraints. When this button is tapped I want a UIlabel to expand out of it to the right edge of the screen. The UIlabel will take up almost the width of the screen and be about 8Points in height. It contains a line of text. It will display for 2 seconds before reversing the animation so that the UILabel shrinks back into the small button. I am new to ios animation and am confused as there are many types! I need to know:
1) What type of animation technique could I use to create this effect? Code would be nice but I'd like to be pointed in the right direction of study.
2) I've read that UILabel can respond inadequately to animations. Is it problematic to animate them in the way I described?
3) Its imperative that the text within the UILabel(and the label itself!) adapts to various screen sizes via some kind of constraint assignment that works hand in hand with the animations. The size/position of the UILabel must be set via autolayout programmatically.
Thanks
UPDATE:
I added this line before the animationWithDuration method(note: (10,5, ....) is where the small button is):
_questionDisplay = [[UILabel alloc]initWithFrame:CGRectMake(10, 5, 0, 30)];
..this line within the first animation block:
_questionDisplay.frame = CGRectMake(10, 5, 600, 30);
..and this line after in the following animationWithDuration method which gets called 3.5 seconds after the first via an NSTimer:
_questionDisplay.frame = CGRectMake(10, 5, 0, 30);
Once the label shrinks it is removed from the view.
This looks good on iPhone6+ but looks wrong in 4s because the label is not being sized with constraints which is what I need.
objective-c
[UILabel animateWithDuration:1
animations:^{
yourView.transform = CGAffineTransformMakeScale(1.5, 1.5);
}
completion:^(BOOL finished) {
[UILabel animateWithDuration:1
animations:^{
yourView.transform = CGAffineTransformIdentity;
}];
}];
Swift
UILabel.animateWithDuration(1, animations: { () -> Void in
yourView.transform = CGAffineTransformMakeScale(1.5, 1.5)
}) { (finished: Bool) -> Void in
UILabel.animateWithDuration(1, animations: { () -> Void in
yourView.transform = CGAffineTransformIdentity
})}
It disappears because you are giving a size explicitly. (If you want multiple screens to size it correctly use equal width(proportional) to superview constraint instead of fixed width. After this, use the method mentioned. When your label will appear, it'll have the correct width due to proportional width constraint and the animation will make it grow and shrink back to its original size. Leave the animation blocks empty (no explicit frame changing!)
Just change the scaling factor(currently 1.2) until it suits you!
1) 2) and 3) are all handled here! The label font itself adjusts so you just need to add the animation
[UIView animateWithDuration:0.5 animations:^{
// grow the label up to 130%, using a animation of 1/2s
yourLabel.transform = CGAffineTransformMakeScale(1.2,1.2); //
} completion:^(BOOL finished) {
// When the "grow" animation is completed, go back to size 100% using another animation of 1/2s
[UIView animateWithDuration:3.5 animations:^{
yourLabel.transform = CGAffineTransformIdentity;
}];
}];
i got a UIImageView which should slide from the top into the view and then when it stops it should make a bounce animation.
I am animating the y.position change like this:
[UIView animateWithDuration:1.3
delay:0.0
options:UIViewAnimationOptionCurveEaseIn
animations:^{
[grassView setFrame:CGRectMake(grassView.frame.origin.x, 425, grassView.frame.size.width, grassView.frame.size.height)];
[headlineView setAlpha:1.0];
[self.loginButton setAlpha:1.0];
// [textView setAlpha:1.0];
[textView setFrame:CGRectMake(textView.frame.origin.x, -136, textView.frame.size.width, textView.frame.size.height)];
}
completion:^(BOOL finished) {
self.usernameField.placeholder = NSLocalizedString(#"username", nil);
self.passwordField.placeholder = NSLocalizedString(#"password", nil);
}];
Don't worry about setting the origin.y coordinate to -136. My image view lays outside the screen at -460 because its height is 450. But when sliding the imageview into the screen i don't want to show the whole image which is why it does not animate to a y.position >= 0. But this part works just fine. My imageview is shown at the correct position where i want it to be. Now i need advise on how to let the imageview bounce when the position was changed. I already tried some CABasicAnimation but it didn't looked like i wanted it to be. Also when i call the method to let the imageview bounce in the completion block of my UIViewAnimation the bouncing effect starts to late.
Does somebody has a hint or idea for me how to get the imageview bounce after the frame was set ?
since iOS7 you can use
[UIView animateWithDuration:<#(NSTimeInterval)#> delay:<#(NSTimeInterval)#> usingSpringWithDamping:<#(CGFloat)#> initialSpringVelocity:<#(CGFloat)#> options:<#(UIViewAnimationOptions)#> animations:<#^(void)animations#> completion:<#^(BOOL finished)completion#> ]
just play around with the damping value and the initial velocity.
I have two UIViews (My bad it is a UIView and a UIButton) which I am animating at the same time. I originally had a view and a containerView which would animate just fine and worked like a charm.
Now only one of my UIViews will move/animate in animateWithDuration even though through debugging the frame of the other view says that it is in a position it is not.
CGRect rect = self.toggle.frame;
CGRect tabRect = self.tabButton.frame;
rect.origin.x = rect.origin.x - rect.size.width;
NSLog(#"%f Before",tabRect.origin.x);
tabRect.origin.x = tabRect.origin.x - rect.size.width;
NSLog(#"%f After", tabRect.origin.x);
[UIView animateWithDuration:0.3 animations:^{ // animate the following:
self.toggle.frame = rect; // move to new location
self.tabButton.frame = tabRect;
}];
NSLog(#"%f AfterAnimation", tabButton.frame.origin.x);
The toggle view moves fine, but the tabButton view does not animate or move. The strange thing is that both the "After" and "AfterAnimation" debugging code returns the same value, which suggests the frame has indeed moved. Is there a specific reason that this will not work when toggle is a UIView when it would work as a UIContainerView?
Note that if I remove the line
self.toggle.frame = rect;
tabButton will animate correctly, but if I move toggle, tabButton will not move regardless of whether it is first in the animation block or second.
Edit: I have tried moving them into separate blocks and to change the center point rather than the frame, to no avail. It seems that if the toggle view moves, the tabButton will not move.
Edit 2: The pictorial evidence.{
In the following screenshots tabButton bg is green and toggle bg is red.
Above: Initial position (toggle is off-screen) correct position
Above: The problem in question toggle is correct tabButton is not
Above: When self.toggle.frame = rect is commented out (tabButton correct, toggle not)
}
Edit 3: It's even worse than I feared.{
I have done a few more tests and even if I take the toggle change out of the animation block to make it an instant thing, the tabButton will still not animate. This makes me think the tabButton may just fundamentally dislike the toggle view and/or myself so will not move just to spite me.
}
Edit 4:{
If I change the tabButton animation to tabButton.frame = CGRectMake(10,10,100,100) the View snaps instantly to that location and animates back to its original position in the same time as the animation duration.
}
I better add more bookkeeping/TLDR information in case things aren't clear.
toggle is an instance of ToggleDraw which is a subview of UIView which I created.
tabButton is a UIButton which is part of my IB viewController and a property of the class
Both toggle and tabButton are subviews of self.view
The animations will work individually with no modifications to the logic of the rects but will not work if they are animated at the same time
toggle animation seems to take precedence over tabButton animation regardless of the order
I had a problem with the animation of an UIView created in IB (the animation didn't start from the current position of the view, and ended in the initial position).
All worked fine after sending layoutIfNeeded() to the underlaying view before the animation block:
self.view.layoutIfNeeded()
UIView.animateWithDuration(0.5) { () -> Void in
...
I think it is not a problem about a UIView Animation. Maybe your toggle posiztion is related to your tabButton. For a try, your can set toggle frame to a rect lick (10, 10, 100,100), then check the result.
I've created an example of what you describe and everything seems to work fine. This is what I used:
UIView *toggle = [[UIView alloc] initWithFrame:CGRectMake(320, 64, 100, 100)];
[toggle setBackgroundColor:[UIColor redColor]];
[self.view addSubview:toggle];
UIButton *tabButton = [[UIButton alloc] initWithFrame:CGRectMake(220, 64, 100, 100)];
[tabButton setBackgroundColor:[UIColor greenColor]];
[self.view addSubview:tabButton];
CGRect rect = toggle.frame;
CGRect tabRect = tabButton.frame;
rect.origin.x = rect.origin.x - rect.size.width;
NSLog(#"%f Before",tabRect.origin.x);
tabRect.origin.x = tabRect.origin.x - rect.size.width;
NSLog(#"%f After", tabRect.origin.x);
[UIView animateWithDuration:1 animations:^{ // animate the following:
toggle.frame = rect; // move to new location
tabButton.frame = tabRect;
}];
What I can suggest is to make sure that the code is being ran on mainthread:
dispatch_async(dispatch_get_main_queue(), ^{
[UIView animateWithDuration:0.3 animations:^{
self.toggle.frame = rect; // move to new location
self.tabButton.frame = tabRect;
}];
});
Also take into account that the log you have after the animation code is incorrect as it won't run after the animation, but rather right next to asking for the animation.
If you want code to run after the animation you should use:
[UIView animateWithDuration:0.3 animations:^{
self.toggle.frame = rect; // move to new location
self.tabButton.frame = tabRect;
} completion:^(BOOL finished){
NSLog(#"Finished animating!");
}];
I have found a solution to the problem. If I initialise the UIButton (tabButton) programmatically rather than through the interface builder, both views will animate simultaneously.
This however seems very hacky to me, kind of like putting a bandaid over a missing foot and hoping it will sort itself out.
I could not work out the root cause of the problem but at least I could avoid the symptoms.
If anyone knows why the views would not animate when the button was made in the interface builder post an answer here, I am interested in knowing the reason behind this.
Thanks for your help everyone.
I have a simple UIView animation block. In the block, I only change the view's alpha, but the view's frame is also being animated! WTF?
Here's my code:
UIButton *button = [flowerViews objectAtIndex:index];
UIImageView *newGlowView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"grid_glow.png"]];
newGlowView.frame = CGRectMake(0, 0, 130, 130);
newGlowView.center = button.center;
newGlowView.alpha = 0.0;
[scrollView_ addSubview:newGlowView];
[scrollView_ sendSubviewToBack:newGlowView];
[UIView animateWithDuration:0.3 animations:^{
newGlowView.alpha = 1.0;
}];
As you see, I'm creating a new view and adding it to scrollView_. I'm setting the view's position and alpha before adding it to scrollView_. Once it's added, I have an animation block to animate the view's alpha from 0 to 1.
The problem is, the view's position is also being animated! As it fades in, it looks as if it's animating from an original frame of CGRectZero to the one I've assigned it.
Ostensibly, only properties set within the animation block should be animated, right? Is this a bug? Am I missing something?
Thanks!
Perhaps the whole thing being called from an animation block or maybe within an event that is within an animation block like the autorotate view controller delegate methods.
I'm trying to move and resize a label, but what happens is the label resizes immediately then moves into position. I first tried simply the commented out lbl.frame line. Next I found this question:
How to animate while resizing UIView
And added all the other code except for the contentMode. This did what I wanted, but the Label's font did not adjust downwards as the label shrunk. ( I tick adjust to fit in xib ). Finally adding the contentMode line gave me the same result as my original frame line - shrink immediately first them animate the move.
lbl.contentMode = UIViewContentModeRedraw;
[UIView animateWithDuration:1.0 delay:0.0
options:(UIViewAnimationOptionAllowUserInteraction)
animations:^{
//lbl.frame = CGRectMake(x, mStartingLine.frame.origin.y+mStartingLine.frame.size.height, 100, 100);
CGRect theBounds = lbl.bounds;
CGPoint theCenter = lbl.center;
theBounds.size.height = 100;
theBounds.size.width = 100;
theCenter.y = mStartingLine.frame.origin.y+mStartingLine.frame.size.height+50;
theCenter.x = x;
lbl.bounds = theBounds;
lbl.center = theCenter;
}
completion:nil
];
I suspect that the auto text resizing feature doesn't work with Core Animation.
What I would suggest doing is to set the label to it's final size (using it's bounds) then apply a transform to it that shrinks it back down to it's starting size. The end effect of those things is that it should stay at the same apparent size.
Finally, use animateWithDuration:animations: to set the view's transform back to the identity transform, so it grows to it's new size.
I don't know what drawing artifacts this will cause - you'll have to try it.