该本仅为笔者自己的理解,如果有不正确的地方,请不吝指教。
当你在实现某个动画效果是,如果想要监听到当前 view 或者 layer 在动画过程中属性的时,可以通过CALayer 的presentationLayer方法来进行获取。
CALayer 中有一个很有意思的方法:
- (nullable instancetype)presentationLayer;
CALayer中包含了一个presentationLayer表示层和modelLayer模型层
如果你对 layer 添加一个animation动画,当动画开始以后,layer的属性其实并没有发行变化,变化的只是 layer 中表示presentationLayer的属性,所有要获取在动画过程中 layer 的属性,可以通过下面的方式获取
@interface ViewController ()<CAAnimationDelegate>{
//CADisplayLink本质就是一个和屏幕内容更新同频率的定时器
CADisplayLink *displayLink;
}
@property (weak, nonatomic) IBOutlet UIView *redView;
@property (nonatomic, strong) CALayer *layer;
@end
@implementation ViewController
- (CADisplayLink *)getDisplayLink{
if (!displayLink) {
//初始化 displayLink
displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLink)];
//将 displayLink 添加到 RunLoop 中
[displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
}
return displayLink;
}
- (void)removeDisplayLink{
[displayLink invalidate];
displayLink = nil;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onRedView)];
[self.redView addGestureRecognizer:tap];
}
- (void)onRedView{
NSLog(@"-----red view 被点击了");
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//给 redView 添加一个在y轴移动的动画
CABasicAnimation *anim = [CABasicAnimation animation];
anim.keyPath = @"position.y";
anim.toValue = @400;
anim.removedOnCompletion = NO;
anim.fillMode = kCAFillModeForwards;
anim.delegate = self;
[_redView.layer addAnimation:anim forKey:nil];
}
#pragma mark - CAAnimationDelegate
- (void)displayLink{
NSLog(@"\nprsention.frame - %@\nmodel.frame - %@\nlayer.frame - %@",NSStringFromCGRect(_redView.layer.presentationLayer.frame), NSStringFromCGRect(_redView.layer.modelLayer.frame), NSStringFromCGRect(_redView.layer.frame));
}
//动画开始
- (void)animationDidStart:(CAAnimation *)anim{
NSLog(@"start-%@",NSStringFromCGRect(_redView.frame));
[self getDisplayLink];
}
//动画结束
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{
// NSLog(@"stop-%@",NSStringFromCGRect(_redView.frame));
NSLog(@"stop-%@",NSStringFromCGRect(_redView.layer.presentationLayer.frame));
[self removeDisplayLink];
}
输出打印结果:
2018-11-02 19:13:22.783428+0800 基础动画[11216:1254495] start-{{0, 20}, {100, 100}}
2018-11-02 19:13:22.784029+0800 基础动画[11216:1254495]
prsention.frame - {{0, 20.95416596159339}, {100, 100}}
model.frame - {{0, 20}, {100, 100}}
layer.frame - {{0, 20}, {100, 100}}
2018-11-02 19:13:22.787055+0800 基础动画[11216:1254495] -----red view 被点击了
2018-11-02 19:13:22.800747+0800 基础动画[11216:1254495]
prsention.frame - {{0, 43.088731914758682}, {100, 100}}
model.frame - {{0, 20}, {100, 100}}
layer.frame - {{0, 20}, {100, 100}}
……
2018-11-02 19:13:23.017459+0800 基础动画[11216:1254495]
prsention.frame - {{0, 329.13446128368378}, {100, 100}}
model.frame - {{0, 20}, {100, 100}}
layer.frame - {{0, 20}, {100, 100}}
2018-11-02 19:13:23.033881+0800 基础动画[11216:1254495]
prsention.frame - {{0, 349.99868214130402}, {100, 100}}
model.frame - {{0, 20}, {100, 100}}
layer.frame - {{0, 20}, {100, 100}}
2018-11-02 19:13:23.034101+0800 基础动画[11216:1254495] stop-{{0, 349.99868214130402}, {100, 100}}
从打印结果可以看出,layer的位置其实是一直没有发生变化的,View 的位置当然也没有,在动画结束后点击移动过的红色 view 的位置其实并不会响应在 view 上添加的 tag 方法,view 的位置其实还是在之前的位置,移动的位置只是 layer 的表现层的 frame。
复杂的动画效果都是通过多种基本的动画组合行程的,比如说通过获取两个不同动画时间的 view 的位移动画,就可以实时的获取到他们之间的一组差值,利用这个差值来再来做一些曲线的变化之类的动画效果就很方便啦。
如果感觉有帮助的话,请点一个喜欢!
网友评论