ios - 使用自动布局时*仅一个*动画 block (UILabel) 的问题

标签 ios xcode animation autolayout constraints

我正在使用自动布局,并且可以毫无问题地对各种约束更改进行动画处理。然而,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];
}

enter image description here

下面是我对标签宽度进行“动画”处理的方法,只有在 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];
}

下面的代码是我根据 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];
    }];
}

最佳答案

我认为使用 NSTimer 制作动画不是一个好方法。

我猜你想要这样的东西:

example

我将标签放入容器 View 中,并为容器 View 的框架设置动画(通过约束)。这是我的场景轮廓:

scene outline

因此,我对标签有宽度和高度约束,并且对容器 View (标签的 super View )也有宽度和高度约束。这些宽度和高度约束的大小并不重要,因为我将在代码中设置它们。我对标签有限制,将其固定在容器的顶部和左侧边缘。我对将其置于其父级(场景的 Root View )中心的容器进行了限制。

我检查了容器的“剪辑 subview ”(在属性检查器中),并将标签的 View 模式设置为“左上”(默认为“左”)。

在我的 View Controller 中,我有标签、标签的宽度和高度约束以及容器的宽度和高度约束的导出:

@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

当 View 加载时,我需要设置小尺寸的约束,所以我假装小按钮被点击,但我禁用动画:

- (void)viewDidLoad {
    [super viewDidLoad];
    [UIView performWithoutAnimation:^{
        [self smallButtonWasTapped:self];
    }];
}

当点击“小”按钮时,我想为容器的框架设置动画。我有一个硬编码的宽度,但我想通过询问标签如果一行高的话它有多高来以编程方式计算出高度。但是,我真的不希望它只有一行高,因此我暂时更改了它的 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;

然后我在动画 block 内执行布局,以便布局更改将以动画方式呈现:

    [UIView animateWithDuration:2 animations:^{
        [self.label.superview layoutIfNeeded];
    }

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

动画完成后,我想显示一个省略号来表示不再可见的内容,因此在完成 block 中,我更改标签的lineBreakMode 和约束:

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

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

当点击“大”按钮时,我想立即去掉省略号并使标签为全尺寸,这样用户就不会看到丢失或重排的文本:

- (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];

然后我可以设置容器的约束以匹配标签的约束,并对布局进行动画处理:

    // Now animate the container.
    self.labelContainerWidthConstraint.constant = self.labelWidthConstraint.constant;
    self.labelContainerHeightConstraint.constant = self.labelHeightConstraint.constant;
    [UIView animateWithDuration:2 animations:^{
        [self.label.superview layoutIfNeeded];
    }];
}

我已经上传了我的项目to this github repository .

关于ios - 使用自动布局时*仅一个*动画 block (UILabel) 的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26181996/

相关文章:

ios - 用条纹填充 UIBezierPath 形状

iphone - 显示特定按钮时如何播放音乐?

ios - CSS 动画不适用于移动设备 [Chrome 或 Safari iOS]

ios - 动画时居中 UIImageView 不起作用

ios - 文件句柄类将整个文件加载到内存中

ios - 从标签栏 Controller 注销到 Root View Controller

ios - 如何让 textview 在 stackview 中滚动并保持可见?

iOS - 将视频上传到数据库然后将它们显示在列表中?

java - 用颜色填充(逐渐)ellispe2D 对象 - Java 动画

ios - NSUserdefault 不适用于 PFObject