Почему анимации на границах UILabel работают только при увеличении размера?

Я заметил, что когда я изменяю границы UILabel в блоке анимации, он работает только, если я увеличиваю размер, когда я уменьшаю размер, UILabel просто меняет свой размер, но не оживляет. Замена UILabel на простой UIView работает по назначению.

Примечание. Изменение свойства contentMode UILabel на UIViewContentModeScaleToFill устраняет эту проблему, но я все еще не понимаю, почему он работает при увеличении размера без изменения свойства contentMode.

#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

Ответы

Ответ 1

Это потому, что UILabel устанавливает свой слой contentsGravity в текстовый текст направления, который по умолчанию имеет значение UIViewContentModeLeft (или @"left"). Таким образом, когда слой сообщается анимации, он сначала рассматривает его содержимое гравитации и основывает на нем последующие анимации. Поскольку он видит @"left", где должен быть @"resize", он предполагает, что анимация масштабирования должна начинаться слева, но она также должна учитывать ограничения, которые вы ей дали (изменения границ), поэтому ваша метка появляется прыгайте в его окончательный размер, затем оседайте там, где он должен находиться в центре экрана.

Если вы хотите оставить только contentMode, используйте CATransform3D и масштабируйте слой метки таким образом вместо изменения границ.