Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Autolayout animate constraint does not animate subviews

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.

like image 359
Christian 'fuzi' Orgler Avatar asked Nov 20 '13 13:11

Christian 'fuzi' Orgler


2 Answers

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.

like image 56
Rivera Avatar answered Oct 20 '22 14:10

Rivera


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];
}
like image 27
rdelmar Avatar answered Oct 20 '22 16:10

rdelmar