I have a UIView which has a UILabel as subview in it.
Now I change the width of the UIView with an animation (changing constant property of constraint) and call layoutIfNeeded in UIView animate...)
The view is resizing normal, but the UILabel (subview) changes the font size to the 'end'-size but didn't animate correctly like the uiview.
According to the WWDC 2012 session the subviews should animate if only the constant of the superview gets changed.
The UILabel has a minimum font scale of 0,1 which is less then the font has to resize.
I was struggling animating a UILabel
resize by changing its width
constraint. The label had adjustsFontSizeToFitWidth
and minimumScaleFactor
set.
I fixed it by setting the labels' contentMode
to UIViewContentModeScaleAspectFit
. By default for labels it is UIViewContentModeLeft
.
I don't think you can animate the size of the text that way. The only way I can think to do this, is by creating a snapshot view of the label, add that view over the label, do the animation, then remove the snapshot view. This code does move the smaller text down slightly, but it looks pretty good, with only a very small movement when you unhide the label and remove the image view. The small view which contains the label was 185x36 in size, and the label had constraints of 20 to each side of smallView and 8 to the top and 7 to the bottom. I add those same constraints in code to the image view.
@interface ViewController ()
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *widthCon; // width constraint on smallView
@property (weak,nonatomic) IBOutlet UIView *smallView; // view that the label is embedded in
@property (weak,nonatomic) IBOutlet UILabel *label;
@end
@implementation ViewController
- (IBAction)shrinkView:(id)sender {
UIView *snapshot = [self.label snapshotViewAfterScreenUpdates:YES];
[snapshot setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.smallView addSubview:snapshot];
[self.smallView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|-20-[snapshot]-20-|" options:0 metrics:nil views:@{@"snapshot":snapshot}]];
NSLayoutConstraint *topCon = [NSLayoutConstraint constraintWithItem:snapshot attribute:NSLayoutAttributeTop relatedBy:0 toItem:self.smallView attribute:NSLayoutAttributeTop multiplier:1 constant:8];
NSLayoutConstraint *bottomCon = [NSLayoutConstraint constraintWithItem:self.smallView attribute:NSLayoutAttributeBottom relatedBy:0 toItem:snapshot attribute:NSLayoutAttributeBottom multiplier:1 constant:7];
[self.smallView addConstraints:@[topCon,bottomCon]];
[self.smallView layoutSubviews];
self.label.alpha = 0;
self.widthCon.constant = 100;
topCon.constant = 18;
bottomCon.constant = 10;
[UIView animateWithDuration:.5 animations:^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
self.label.alpha = 1;
[snapshot removeFromSuperview];
}];
}
After Edit:
There is a way to animate the view so that the label also animates down rather than going immediately to its end size. You have to animate the constraint directly with a timer (Look at the explanation at about 31 minutes into the WWDC 2012 video, "Best Practices for Mastering Auto Layout"). This works to animate the label's size, but the font size change is jumpy, and doesn't look that good. If you have a width constraint to the view that the label is in (and the label has constraints to the two sides), then you can do this:
-(IBAction)animateSizeChange:(id)sender {
[NSTimer scheduledTimerWithTimeInterval:.001 target:self selector:@selector(doStuff:) userInfo:Nil repeats:YES];
}
-(void)doStuff:(NSTimer *) aTimer {
self.widthCon.constant -= .2;
if (self.widthCon.constant <90) [aTimer invalidate];
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With