最近在做一个类似iOS最新版QQ提示框的控件,遇到了一些小问题,因为QQ的提示框是在点击的时候就自动弹回去,那么首先就要解决一个UIView的动画如何接收点击事件,但是对于UIView的frame动画来说,只要是改变了frame的动画都不能点击,哪怕你设置了可以点击,UIView的animation方法也设置了可以点击的type,但依然不管用的。
既然没法用UIView的动画,那么就在进一层,用Layer动画,那这样就跟View没有关系了,View自然可以接收点击事件。
那么问题来了,在CAAnimation的代理方法里面,并没有直接区分是哪个动画开始,哪个动画结束的方法,看了看官方文档,也没有在代理方法中给出判断的方法,那么就只能自己研究一下了。。
在NSObject里有一个很有用的方法,叫
- (void)setValue:(nullable id)value forKey:(NSString *)key;
这个方法可以为对象存一个键值对,用来个性化判断。既然找到了方法,那么一切就非常好办了。
例子如下。其中self.animView是一个全局变量,用来改变View位置的。因为Layer动画不会改变view本身的位置,所以需要重新设置。
UIView * vc = [[UIView alloc] initWithFrame:CGRectMake(0, 0, width, height)];
vc.layer.frame = CGRectMake(0, -height, width, height);
vc.backgroundColor = [UIColor redColor];
[vc addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(stopVCAnimation:)]];
self.animView = vc;
[self.view addSubview:vc];
CABasicAnimation * animation1 = [CABasicAnimation animationWithKeyPath:@"position"];
animation1.delegate = self;
animation1.fromValue = [NSValue valueWithCGPoint:CGPointMake(width/2, -height/2)];
animation1.toValue = [NSValue valueWithCGPoint:CGPointMake(width/2, height/2)];
animation1.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
animation1.autoreverses = NO;
animation1.removedOnCompletion = NO;
animation1.fillMode = kCAFillModeForwards;
animation1.beginTime = CACurrentMediaTime() + 2;
animation1.duration = 0.25;
//这里的AnimationKey应该写成一个宏定义,偷个懒。
[animation1 setValue:@"StartShowAnimation" forKey:@"AnimationKey"];
[vc.layer addAnimation:animation1 forKey:@"StartShowAnimation"];
CABasicAnimation * animation2 = [CABasicAnimation animationWithKeyPath:@"position"];
animation2.delegate = self;
animation2.fromValue = [NSValue valueWithCGPoint:CGPointMake(width/2, height/2)];
animation2.toValue = [NSValue valueWithCGPoint:CGPointMake(width/2, -height/2)];
animation2.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
animation2.autoreverses = NO;
animation2.removedOnCompletion = NO;
animation2.fillMode = kCAFillModeForwards;
animation2.beginTime = CACurrentMediaTime() + 4;
animation2.duration = 0.25;
//这里的AnimationKey应该写成一个宏定义,偷个懒。
[animation2 setValue:@"StartHiddenAnimation" forKey:@"AnimationKey"];
[vc.layer addAnimation:animation2 forKey:@"StartHiddenAnimation"];
这里是点击事件的方法:
- (void)stopVCAnimation:(UITapGestureRecognizer *)sender {
UIView * v = sender.view;
[v.layer removeAnimationForKey:@"StartHiddenAnimation"];
CABasicAnimation * animation2 = [CABasicAnimation animationWithKeyPath:@"position"];
animation2.fromValue = [NSValue valueWithCGPoint:CGPointMake(v.center.x, v.center.y)];
animation2.toValue = [NSValue valueWithCGPoint:CGPointMake(v.center.x, -v.center.y)];
animation2.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
animation2.autoreverses = NO;
animation2.removedOnCompletion = NO;
animation2.fillMode = kCAFillModeForwards;
animation2.beginTime = CACurrentMediaTime();
animation2.duration = 0.25;
[animation2 setValue:@"StartHiddenAnimation" forKey:@"AnimationKey"];
[v.layer addAnimation:animation2 forKey:@"StartHiddenAnimation"];
}
代理方法:
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
if (flag) {
CABasicAnimation * animation = (CABasicAnimation *)anim;
if ([[anim valueForKey:@"AnimationKey"] isEqualToString:@"StartShowAnimation"]) {
NSLog(@"StartShowAnimation End");
self.animView.center = CGPointMake(self.animView.center.x, 32);
}else if ([[animation valueForKey:@"AnimationKey"] isEqualToString:@"StartHiddenAnimation"]) {
NSLog(@"StartHiddenAnimation End");
self.animView.center = CGPointMake(self.animView.center.x, -32);
}
}
}