22

I noticed that when i change the bounds of an UILabel in an animation block it only works if i increase the size, when i decrease the size the UILabel just changes his size but doesn't animate. Replacing the UILabel with a plain UIView works as intended.

Note: Changing the contentMode property of the UILabel to UIViewContentModeScaleToFill fixes this issue, but i still don't understand why it works when increasing the size without changing the contentMode property.

#import "FooView.h"

@interface FooView ()
@property (strong, nonatomic) UILabel   *label;
@property (assign, nonatomic) BOOL       resized;
@end

@implementation FooView

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        self.backgroundColor = [UIColor lightGrayColor];

        self.label = [[UILabel alloc] initWithFrame:(CGRect){0, 0, frame.size}];
        self.label.backgroundColor = [UIColor greenColor];
        [self addSubview:self.label];
        _resized = false;

        UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(changeSize)];
        tapRecognizer.numberOfTapsRequired = 1;
        [self addGestureRecognizer:tapRecognizer];
    }
    return self;
}

- (void)changeSize {
    [UIView animateWithDuration:0.8
                          delay:0.0
                        options:UIViewAnimationOptionCurveEaseIn
                     animations:^{
                         CGRect bounds = self.label.bounds;
                         if (self.resized) {
                             bounds.size.height *= 2;
                             bounds.size.width  *= 2;
                         } else {
                             bounds.size.width  /= 2;
                             bounds.size.height /= 2;
                         }
                         self.label.bounds = bounds;
                     }
                     completion:^(BOOL finished) {
                         self.resized = !self.resized;
                     }];
}

@end
Tom van Zummeren
  • 9,130
  • 12
  • 52
  • 63
peko
  • 11,267
  • 4
  • 33
  • 48
  • You have the answer here: http://stackoverflow.com/questions/3298764/animating-uilabel-size-decrease – Amit Jun 28 '13 at 08:36
  • @amit3117 no this doesn' explain why, and i'm allready changing the the bounds not the frame – peko Jun 28 '13 at 08:39
  • i just setup your code and im wondering if you're seeing the same effect i am seeing, the bounds grows with animation, but when you tap again it "snaps" back to small size although i notice my centered text is animating back just as it did while growing....just background color had a snap like effect only when resizing to small label – rezand Jul 01 '13 at 03:08
  • @rezand yes that's what im seeing too – peko Jul 01 '13 at 08:14
  • That this is inconsistent (see Amit's link to 3298764) strikes me as a bug. I have filed it with Apple: Bug ID# 14340799. – Olie Jul 03 '13 at 03:42
  • @Olie any response yet? – peko Jul 04 '13 at 09:59
  • I'll post here when I get a useful response. So far, they only asked if it was the same in iOS7. – Olie Jul 04 '13 at 14:49

1 Answers1

25

It's because UILabel sets its layer's contentsGravity to the direction text is being rendered, which happens to default to UIViewContentModeLeft (or @"left"). Thus, when the layer is told to animate, it first takes a glance at its contents gravity and bases subsequent animations on that. Because it sees @"left" where there should be @"resize", it assumes that the scaling animation should begin from the left, but it also has to respect the constraints you've given it (the bounds changes), so your label appears to jump into its final size then settle where it should in the center of the screen.

If you want to leave contentMode alone, use CATransform3D's and scale the label's layer that way instead of a bounds change.

CodaFi
  • 43,043
  • 8
  • 107
  • 153