技术感(Che)悟(Dan)(可跳过)
遇到某技术问题时,第一眼看起来实现特别复杂,但又没有更好的思路,只有硬着头皮做下去。耗费了巨大的时间和精力,最终完成,成就感爆棚的同时却总感觉不够优雅。无奈开发任务紧迫,只好搁置。待到闲暇时光(不存在的,唠嗑、斗图都是正经事好不好😜),细思起来不是实现复杂,而是思路偏了,找到最优解,才是我辈进取(装逼)之路。
俗话说:不折腾开发的二货不是好产品,设计之初是用个短视频作为背景,话不多说,BackgroundVideoiOS 搬砖完毕。然而事情怎会如此顺利,运营给出视频太大,压缩后又模糊不清,此方案只好作罢。
那就用图片自己做呗,毕竟有多年Banner经验,此事应该不难,然而真是这样?图片轮播展示完毕的切换卡顿,哪可能逃过产品Dog(就说了能咋地?)的法眼。下面才是入坑的开始:思路是两张一样的图片并排排列,首尾相连,同时左移,设置相同动画时间,X值不断减小,动画结束回调Frame重置方法,递归回调
#import <UIKit/UIKit.h>
typedef void(^MoveAnimationBlock)(void);
@interface MoveAnimationView : UIView
/**
向左移动
@param view 视图
@param timer 时间
@param block 回调方法
*/
+ (void)leftTranslationAnimationView:(UIView *)view
animationDuration:(NSTimeInterval)timer
animationBlock:(MoveAnimationBlock)block;
@end
#import "MoveAnimationView.h"
@implementation MoveAnimationView
+ (void)leftTranslationAnimationView:(UIView *)view animationDuration:(NSTimeInterval)timer animationBlock:(MoveAnimationBlock)block {
[UIView animateWithDuration:timer delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
CGRect frame = view.frame;
frame.origin.x = frame.origin.x - frame.size.width;
view.frame = frame;
} completion:^(BOOL finished) {
if (finished) {
block();
}
}];
}
@end
为了解决,跳出当前页面返回后动画停止的问题,需在viewWillAppear方法中调用:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self startMoveAnimation];
}
- (void)startMoveAnimation {
UIImage *bgImg = [UIImage imageNamed:@"first_login_bg.jpg"];
CGFloat width = 1.f * bgImg.size.width / bgImg.size.height * kScreenHeight;
self.bgImgV_1.frame = CGRectMake(0, 0, width, kScreenHeight);
self.bgImgV_2.frame = CGRectMake(width, 0, width, kScreenHeight);
[self moveBgImgV_1Animation];
[self moveBgImgV_2Animation];
}
- (UIImageView *)bgImgV_1 {
if (!_bgImgV_1) {
_bgImgV_1 = [[UIImageView alloc]initWithFrame:CGRectZero];
_bgImgV_1.image = [UIImage imageNamed:@"first_login_bg.jpg"];
}
return _bgImgV_1;
}
- (UIImageView *)bgImgV_2 {
if (!_bgImgV_2) {
_bgImgV_2 = [[UIImageView alloc]initWithFrame:CGRectZero];
_bgImgV_2.image = [UIImage imageNamed:@"first_login_bg.jpg"];
}
return _bgImgV_2;
}
- (void)moveBgImgV_1Animation
{
WeakSelf
[MoveAnimationView leftTranslationAnimationView:self.bgImgV_1 animationDuration:36 animationBlock:^{
CGRect frame = _self.bgImgV_1.frame;
frame.origin.x =_self.bgImgV_1.width;
//右移动
//frame.origin.x = 0;
_self.bgImgV_1.frame = frame;
[_self moveBgImgV_1Animation];
}];
}
- (void)moveBgImgV_2Animation
{
WeakSelf
[MoveAnimationView leftTranslationAnimationView:self.bgImgV_2 animationDuration:36 animationBlock:^{
CGRect frame = _self.bgImgV_2.frame;
frame.origin.x = 0;
//右移动
//frame.origin.x = -_self.bgImgV_2.width;
_self.bgImgV_2.frame = frame;
[_self moveBgImgV_2Animation];
}];
}
貌似完美解决,可以交工喝茶了,然而如最初所言,总是感觉不够优雅,还有跳出再返回此页面动画总是重头开始。
下面敲黑板,重点来了,如何用核心动画打开尴尬局面,说干就干:
- (void)startMoveAnimation {
UIImage *bgImg = [UIImage imageNamed:@"first_login_bg.jpg"];
CGFloat width = 1.f * bgImg.size.width / bgImg.size.height * kScreenHeight;
UIImageView *bgImgV_1 = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, width, kScreenHeight)];
bgImgV_1.image = bgImg;
UIImageView *bgImgV_2 = [[UIImageView alloc] initWithFrame:CGRectMake(width, 0, width, kScreenHeight)];
bgImgV_2.image = [UIImage imageNamed:@"first_login_bg.jpg"];
[self.view addSubview:bgImgV_2];
[self.view addSubview:bgImgV_1];
CFTimeInterval duration = 36;
CABasicAnimation *anim1 = [CABasicAnimation animationWithKeyPath:@"transform.translation.x"];
anim1.toValue = @(-width);
anim1.duration = duration;
anim1.repeatCount = HUGE_VALF;
anim1.removedOnCompletion = NO; //解决页面切换之后,动画久停止的问题,其实是
[bgImgV_1.layer addAnimation:anim1 forKey:nil];
CABasicAnimation *anim2 = [CABasicAnimation animationWithKeyPath:@"transform.translation.x"];
anim2.toValue = @(-width);
anim2.duration = duration;
anim2.repeatCount = HUGE_VALF;
anim2.removedOnCompletion = NO;
[bgImgV_2.layer addAnimation:anim2 forKey:nil];
}
CABasicAnimation使用总结
解释:为什么动画结束后返回原状态?
首先我们需要搞明白一点的是,layer动画运行的过程是怎样的?其实在我们给一个视图添加layer动画时,真正移动并不是我们的视图本身,而是 presentation layer 的一个缓存。动画开始时 presentation layer开始移动,原始layer隐藏,动画结束时,presentation layer从屏幕上移除,原始layer显示。这就解释了为什么我们的视图在动画结束后又回到了原来的状态,因为它根本就没动过。
这个同样也可以解释为什么在动画移动过程中,我们为何不能对其进行任何操作。
所以在我们完成layer动画之后,最好将我们的layer属性设置为我们最终状态的属性,然后将presentation layer 移除掉。
至此效果上看来是够优雅了,代码不优雅的地方欢迎指正!