UIImageView动画切换图片时同步变更文本的问题排查
问题
在App中需要实现一个可重复运行直到触发操作的动画,要求图片与文本同步切换。目前尝试使用关键帧动画,但仅显示最后一次变更且无法重复。已知animateKeyframesWithDuration单位为秒,相对开始时间和时长取值0-1,因有5个帧故设为0.2,但所有NSLog均触发,仅最终状态生效,请问问题出在哪里?
代码如下:
[UIView animateKeyframesWithDuration:70 delay:0 options:UIViewKeyframeAnimationOptionRepeat animations:^{ [UIView addKeyframeWithRelativeStartTime:0 relativeDuration:0.2 animations:^{ NSLog(@"a1"); self.eventsText.text = nil; theImageView.image = [UIImage imageNamed:@"welcome.png"]; }]; [UIView addKeyframeWithRelativeStartTime:0.2 relativeDuration:0.2 animations:^{ NSLog(@"a12"); theImageView.image = [UIImage imageNamed:@"pleasepray.png"]; self.eventsText.text = @"Test2"; }]; [UIView addKeyframeWithRelativeStartTime:0.4 relativeDuration:0.2 animations:^{ NSLog(@"a13"); theImageView.image = [UIImage imageNamed:@"comingevents.png"]; self.eventsText.text = @"Test3"; }]; [UIView addKeyframeWithRelativeStartTime:0.6 relativeDuration:0.2 animations:^{ NSLog(@"a14"); theImageView.image = [UIImage imageNamed:@"birthdays.png"]; self.eventsText.text = nil; }]; [UIView addKeyframeWithRelativeStartTime:0.8 relativeDuration:0.2 animations:^{ NSLog(@"a14"); theImageView.image = [UIImage imageNamed:@"ournumbers.png"]; self.eventsText.text = @"Test4"; }]; } completion:nil];
解决方案
问题核心是直接在关键帧动画块中修改视图的真实属性,而非通过动画系统处理过渡。UIView关键帧动画默认作用于视图的layer层,但直接修改text、image这类属性会立即更新视图的真实状态,所有关键帧的修改会被最后一次覆盖,最终仅保留最终状态。
修正步骤
- 提前设置初始状态:在动画启动前,先把视图设置为第一个关键帧的状态,不要放在第一个关键帧块内。
- 用过渡动画处理内容切换:对
UIImageView的图片和UILabel的文本切换,使用transitionWithView添加过渡效果,确保动画系统能捕捉到状态变化。 - 保证重复时的状态循环:如果需要重复动画,可配合
UIViewKeyframeAnimationOptionAutoreverse让动画反向循环,或在重复时手动重置初始状态。
修改后的示例代码
// 先设置初始状态 self.eventsText.text = nil; theImageView.image = [UIImage imageNamed:@"welcome.png"]; [UIView animateKeyframesWithDuration:70 delay:0 options:UIViewKeyframeAnimationOptionRepeat | UIViewKeyframeAnimationOptionAutoreverse animations:^{ [UIView addKeyframeWithRelativeStartTime:0.2 relativeDuration:0.2 animations:^{ NSLog(@"a12"); [UIView transitionWithView:theImageView duration:0 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{ theImageView.image = [UIImage imageNamed:@"pleasepray.png"]; } completion:nil]; [UIView transitionWithView:self.eventsText duration:0 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{ self.eventsText.text = @"Test2"; } completion:nil]; }]; [UIView addKeyframeWithRelativeStartTime:0.4 relativeDuration:0.2 animations:^{ NSLog(@"a13"); [UIView transitionWithView:theImageView duration:0 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{ theImageView.image = [UIImage imageNamed:@"comingevents.png"]; } completion:nil]; [UIView transitionWithView:self.eventsText duration:0 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{ self.eventsText.text = @"Test3"; } completion:nil]; }]; [UIView addKeyframeWithRelativeStartTime:0.6 relativeDuration:0.2 animations:^{ NSLog(@"a14"); [UIView transitionWithView:theImageView duration:0 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{ theImageView.image = [UIImage imageNamed:@"birthdays.png"]; } completion:nil]; [UIView transitionWithView:self.eventsText duration:0 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{ self.eventsText.text = nil; } completion:nil]; }]; [UIView addKeyframeWithRelativeStartTime:0.8 relativeDuration:0.2 animations:^{ NSLog(@"a14"); [UIView transitionWithView:theImageView duration:0 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{ theImageView.image = [UIImage imageNamed:@"ournumbers.png"]; } completion:nil]; [UIView transitionWithView:self.eventsText duration:0 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{ self.eventsText.text = @"Test4"; } completion:nil]; }]; } completion:nil];
补充说明
- 若不需要反向动画,可移除
UIViewKeyframeAnimationOptionAutoreverse,但需在动画完成后手动重置初始状态并重新触发动画(需额外处理停止逻辑)。 - 直接修改视图属性会绕过动画系统,所有关键帧的属性修改会在动画启动前就全部生效,这就是为何
NSLog都触发了却看不到中间状态的原因。
内容的提问来源于stack exchange,提问作者user717452
相关产品推荐
相关产品推荐

