问题*只有一个*动画块(UILabel)使用AutoLayout

Jer*_*ero 2 xcode animation constraints ios autolayout

我正在使用AutoLayout并且正在动画各种约束更改而没有任何问题.但是,VC中有一个UILabel根本不会动画.我想要的动画是一种擦拭效果.我已经设置了一个计时器,根据rdelmar的建议,因为UILabel不支持动画约束,并且我正在获得我想要的只有一行长的标签的效果.但是,多行的标签不会产生类似擦拭的效果,而是字符会换行,并且标签的宽度会增加.下面是我如何设置标签的约束.

- (void)initializeLabelWithMessage:(NSDictionary *)message {
    meaningLabel.text = [messagingSubMethods meaningStringForLabelFromMessage:message];        
    meaningLabel.numberOfLines = _expectedNumberOfLines;

    float meaningLabelHeight;
    if (_expectedNumberOfLines == 2) {
        meaningLabelHeight = 32;
    } else if (_expectedNumberOfLines == 3) {
        meaningLabelHeight = 48;
    } else {
        meaningLabelHeight = 18;
    }

    _meaningWidthConstraint.constant = 0;
    _meaningHeightConstraint.constant = meaningLabelHeight;
    [self.view layoutIfNeeded];
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

下面是我的'动画'标签宽度的方法,只有当numberOfLines为1时,才能给出我想要的效果.

- (void)startMeaningAnimationTimer {
    _meaningAnimationTimer = [NSTimer timerWithTimeInterval:0.05 target:self selector:@selector(increaseMeaningLabelWidth) userInfo:nil repeats:YES];
    [[NSRunLoop mainRunLoop] addTimer:_meaningAnimationTimer forMode:NSDefaultRunLoopMode];
    [_meaningAnimationTimer fire];
}

- (void)increaseMeaningLabelWidth {
    if (_meaningWidthConstraint.constant < _expectedMeaningWidth) {
        _meaningWidthConstraint.constant = _meaningWidthConstraint.constant + 1;
        [self.view layoutIfNeeded];
    } else
        [self stopMeaningAnimationTimer];
}
Run Code Online (Sandbox Code Playgroud)

以下代码是我在Rob的建议之后添加的代码.第一个是我最初尝试将他的代码与我的代码集成.第二次尝试是看我能否"复制并粘贴"他的代码.

- (void)attempt1 {
    _meaning1WidthConstraint.constant = 0;
    [self.view layoutIfNeeded];
    [UIView animateWithDuration:0.5 animations:^{
        _meaningWidthConstraint.constant = expectedWidth;
        [self.view layoutIfNeeded];
    } completion:^(BOOL finished) {
        _meaning1WidthConstraint.constant = expectedWidth;
        [self.view layoutIfNeeded];
    }];
}

- (void)attempt2 {
    _meaning1WidthConstraint.constant = [meaningLabel1 sizeThatFits:CGSizeMake(expectedWidth, CGFLOAT_MAX)].width;
    [meaningLabel1 layoutIfNeeded];

    // Now animate the container.
    _meaning1WidthConstraint.constant = _meaning1WidthConstraint.constant;
    [UIView animateWithDuration:2 animations:^{
        [meaningLabel1.superview layoutIfNeeded];
    }];
}
Run Code Online (Sandbox Code Playgroud)

rob*_*off 5

我不认为使用NSTimera 动画是一种很好的方法.

我想你想要这样的东西:

例

我将标签放在容器视图中,并为容器视图的框架设置动画(通过约束).这是我的场景大纲:

场景轮廓

所以,我在标签上有宽度和高度限制,并且我在容器视图(标签的超视图)上也有宽度和高度限制.这些宽度和高度约束的大小并不重要,因为我将在代码中设置它们.我对标签有限制,将其固定到容器的顶部和左侧边缘.我对容器的约束在其父对象(场景的根视图)中居中.

我检查了容器的"剪辑子视图"(在属性检查器中),并且我将标签的视图模式设置为"左上角"(默认为"左").

在我的视图控制器中,我有标签的出口,标签的宽度和高度约束,以及容器的宽度和高度约束:

@interface ViewController ()
@property (strong, nonatomic) IBOutlet UILabel *label;
@property (strong, nonatomic) IBOutlet NSLayoutConstraint *labelContainerWidthConstraint;
@property (strong, nonatomic) IBOutlet NSLayoutConstraint *labelContainerHeightConstraint;
@property (strong, nonatomic) IBOutlet NSLayoutConstraint *labelWidthConstraint;
@property (strong, nonatomic) IBOutlet NSLayoutConstraint *labelHeightConstraint;
@end
Run Code Online (Sandbox Code Playgroud)

当视图加载时,我需要设置小尺寸的约束,所以我假装轻按了小按钮,但我禁用了动画:

- (void)viewDidLoad {
    [super viewDidLoad];
    [UIView performWithoutAnimation:^{
        [self smallButtonWasTapped:self];
    }];
}
Run Code Online (Sandbox Code Playgroud)

点击"小"按钮时,我想为容器的框架设置动画.我有一个硬编码的宽度,但我想通过询问标签,如果它是一条线高,它会以编程方式计算出高度.但是,我真的不希望它是一行高,所以我numberOfLines暂时改变它:

- (IBAction)smallButtonWasTapped:(id)sender {
    self.labelContainerWidthConstraint.constant = 150;
    self.label.numberOfLines = 1;
    self.labelContainerHeightConstraint.constant = [self.label sizeThatFits:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)].height;
    self.label.numberOfLines = 0;
Run Code Online (Sandbox Code Playgroud)

然后我在动画块内执行布局,以便布局更改动画:

    [UIView animateWithDuration:2 animations:^{
        [self.label.superview layoutIfNeeded];
    }
Run Code Online (Sandbox Code Playgroud)

请注意,我没有修改标签的约束,因此它将保持相同的框架和内容.它不会回流,这似乎是你的主要抱怨.

当动画结束时,我想显示一个省略号来表示不再可见的内容,所以在完成块中,我确实更改了标签lineBreakMode和约束:

      completion:^(BOOL finished) {
        if (finished) {
            self.label.lineBreakMode = NSLineBreakByTruncatingTail;
            self.labelWidthConstraint.constant = self.labelContainerWidthConstraint.constant;
            self.labelHeightConstraint.constant = self.labelContainerHeightConstraint.constant;
        }
    }];
Run Code Online (Sandbox Code Playgroud)

但我没有为布局设置动画,因此标签会立即更改为显示省略号.

当点击"大"按钮时,我想立即删除省略号并使标签全尺寸,以便用户不会看到丢失或回流文本:

- (IBAction)bigButtonWasTapped:(id)sender {
    // First, get rid of the ellipsis and resize the label without animation.
    self.label.lineBreakMode = NSLineBreakByWordWrapping;
    self.label.numberOfLines = 0;
    self.labelWidthConstraint.constant = 300;
    self.labelHeightConstraint.constant = [self.label sizeThatFits:CGSizeMake(self.labelWidthConstraint.constant, CGFLOAT_MAX)].height;
    [self.label layoutIfNeeded];
Run Code Online (Sandbox Code Playgroud)

然后我可以设置容器的约束以匹配标签,并为布局设置动画:

    // Now animate the container.
    self.labelContainerWidthConstraint.constant = self.labelWidthConstraint.constant;
    self.labelContainerHeightConstraint.constant = self.labelHeightConstraint.constant;
    [UIView animateWithDuration:2 animations:^{
        [self.label.superview layoutIfNeeded];
    }];
}
Run Code Online (Sandbox Code Playgroud)

我已将我的项目上传到此github存储库.