我想用UIViewAnimation构建交互式过渡。但是我可以为它设置动画的几层属性。所以我决定使用CAAnimation。 我想更改ViewController的视图掩码,这是代码
-(NSTimeInterval)transitionDuration:(nullable id<UIViewControllerContextTransitioning>)transitionContext{
return 0.5f;
}
-(void)animateTransition:(nonnull id<UIViewControllerContextTransitioning>)transitionContext{
_transitionContext=transitionContext;
UIViewController *fromVC=
[transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toVC=
[transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIView *containerView=[transitionContext containerView];
_toVC=toVC;
_fromVC=fromVC;
[containerView insertSubview:toVC.view aboveSubview:fromVC.view];
//Create the BezierPath
UIBezierPath *initailPath=[UIBezierPath bezierPathWithRect:(CGRect) {{_cellRect.size.width/2,_cellRect.origin.y+_cellRect.size.height/2},.size= {0.5,0.5}}];
CGFloat radius;
CGFloat distance;
if (fromVC.view.frame.size.width>fromVC.view.frame.size.height) {
distance=fromVC.view.frame.size.width-_cellRect.origin.x;
radius=distance>_cellRect.origin.x?distance:_cellRect.origin.x+88;
}else{
distance=fromVC.view.frame.size.height-_cellRect.origin.y;
radius=distance>_cellRect.origin.y?distance:_cellRect.origin.y+88;
}
radius=radius*2;
UIBezierPath *finalPath=[UIBezierPath bezierPathWithOvalInRect:CGRectInset(_cellRect,
- radius,
- radius)];
_initaialPath=initailPath;
_finalPath=finalPath;
//Create a Layer Mask
_maskLayer=[[CAShapeLayer alloc] init];
_maskLayer.path=finalPath.CGPath;
toVC.view.layer.mask=_maskLayer;
[self animateLayer:_maskLayer withCompletion:^{
BOOL isComple=![transitionContext transitionWasCancelled];
if (!isComple) {
[containerView addSubview:fromVC.view];
[toVC.view removeFromSuperview];
}
[transitionContext completeTransition:isComple];
}];
}
-(void)startInteractiveTransition:(nonnull id<UIViewControllerContextTransitioning>)transitionContext{
_transitionContext=transitionContext;
[self animateTransition:transitionContext];
[self pauseTime:[_transitionContext containerView].layer];
}
这是主要的动画,它完美无需互动。 然后我试着用这些代码控制它:
-(void)updateInteractiveTransition:(CGFloat)percentComplete{
[_transitionContext updateInteractiveTransition:percentComplete];
[_transitionContext containerView].layer.timeOffset=_pausedTime + [self transitionDuration:_transitionContext]*percentComplete;
}
-(void)finishInteractiveTransition{
[_transitionContext finishInteractiveTransition];
[self resumeTime:[_transitionContext containerView].layer];
}
这两个功能完美无缺
但是这里是问题&#34;取消转换&#34; 当我取消过渡时,它会突然消失 (我已尝试使用此解决方案question但这对我不起作用) 这是我的代码:
- (void)cancelInteractiveTransition {
//Must Cancel System InteractiveTransition FRIST
[_transitionContext cancelInteractiveTransition];
//Then adjust the layer time
CALayer *maskLayer =[_transitionContext containerView].layer;
maskLayer.beginTime = CACurrentMediaTime();
//MOST IMPORTANT
[UIView animateWithDuration:0.5 animations:^{
maskLayer.timeOffset=0.0;
} completion:^(BOOL finished) {
[[_transitionContext containerView ] addSubview:_fromVC.view];
[_toVC.view removeFromSuperview];
}];
}
现在我差不多花了整整一周的时间,如果你可以帮助我,我真的可以预测。
答案 0 :(得分:3)
我们可以轻松地将图层的属性从初始值设置为最终值。 通常,当我们想要实现交互式动画时,我们可以使用UIView的动画块来达到此目的(转到最终位置或返回到原始位置)。但是你不能用像BackgroundColour,CGPath这样的属性来做这件事。
我们可以通过使用CAAnimation控制进程,并控制 CALayer的时间偏移。当我们在一些精确的位置控制动画过程时。我们怎样才能回到动画过程?如果您控制的财产是位置。
[UIView animateWithDuration:/*Left time*/
delay:/*delay time*/
usingSpringWithDamping:/*damping*/
initialSpringVelocity:/*speed*/
options:/*option*/
animations:^{
/*Your animation*/
} completion:^(BOOL finished) {
}];
但它不适合像CGPath或BackgroundColor这样的东西。
我们需要一种驱动动画的方法,苹果支持驱动程序,此驱动程序将调用您指定的功能。它将像iPhone屏幕一样每秒执行60次。 该技术是 CADisplayLink 对象。它是一个计时器对象,允许您的应用程序将绘图与显示的刷新率同步。
然后我得到了解决方案:
if (!_displayLink) {
_displayLink=[CADisplayLink displayLinkWithTarget:self selector:@selector(animationTick:)];
[_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
}
AnimationTick功能是您刷新的功能:
-(void)animationTick:(CADisplayLink *)displayLink{
CALayer *maskLayer=[_transitionContext containerView].layer;
CGFloat timeOffset=maskLayer.timeOffset;
timeOffset=MAX(0,timeOffset-_piceDistance);
maskLayer.timeOffset=timeOffset;
if (timeOffset==0) {
displayLink.paused=YES;
}
}
全部