iOS7教程系列:自定义导航转场动画以及更多http://www.cocoachina.com/ios/20131224/7597.html
viewController 转场 http://objccn.io/issue-5-3/
自定义控制器转场动画及下拉菜单的小Demo http://wxgbridgeq.github.io/blog/2015/08/10/custom-transition-animation/
iOS自定义转场详解01 - UIViewControllerTransition的用法 http://kittenyang.com/uiviewcontrollertransitioning/
iOS自定义转场详解02 - 实现Keynote中的神奇效果 http://kittenyang.com/magicmove/
iOS自定义转场详解03 - 实现通过圆圈放大缩小的转场动画 http://kittenyang.com/pingtransition/
iOS自定义转场详解04 - 实现3D翻转效果 http://kittenyang.com/3dfliptransition/
自定义转场动画库 https://github.com/ColinEberhardt/VCTransitionsLibrary
http://www.ios122.com/tag/vctransitionslibrary/
//iOS7中增加了2个新的基于block的方法 这样可以很少直接使用Core Animation
//关键帧动画 只需要将每一帧动画加入到block方法中,并传入此段动画在全过程中的相对开始时间和执行时间
[UIView animateKeyframesWithDuration:0
delay:0
options:0
animations:^{
//addKeyframe添加关键帧到动画执行栈
/**
* StartTime:相对开始时间 Duration:执行时间
*/
[UIView addKeyframeWithRelativeStartTime:0.0
relativeDuration:0.5
animations:^{
//第一帧要执行动画
}];
[UIView addKeyframeWithRelativeStartTime:0.5
relativeDuration:0.5
animations:^{
//第二帧要执行动画
}];
} completion:^(BOOL finished) {
//动画结束执行
}];
//弹簧动画
/**
:damping 弹性阻尼 越接近0弹性效果越明显 如设成1不会有弹性效果
:velocity 弹性修正速度 它表示视图在弹跳时恢复原位的速度,例如,如果在动画中视图被
拉伸的最大距离是200像素,你想让视图以100像素每秒的速度恢复原位,那么就设置velocity的值为0.5
*/
[UIView animateWithDuration:1
delay:0
usingSpringWithDamping:0.8
initialSpringVelocity:1.0
options:0
animations:^{
} completion:^(BOOL finished) {
}];
苹果公司提供了一个新的协议:UIViewControllerAnimatedTransitioning,
我们可以在协议方法中编写自定义的动画代码。苹果开发者文档中称实现了此协议的对象为 动画控制器
由于我们使用了协议这一语法特性,自定义动画的代码可以灵活的放在自己想要的位置。
它定义了一些通用的属性和助手方法
@protocol UIViewControllerAnimatedTransitioning <NSObject>
- (NSTimeInterval)transitionDuration:(nullable id <UIViewControllerContextTransitioning>)transitionContext;
//自定义转场动画
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext;
//它在动画完成后由系统自动调用,相当于completion block
@optional
- (void)animationEnded:(BOOL) transitionCompleted;
@end
UIViewControllerTransitioning.h中
UIKIT_EXTERN NSString *const UITransitionContextFromViewControllerKey NS_AVAILABLE_IOS(7_0);
UIKIT_EXTERN NSString *const UITransitionContextToViewControllerKey NS_AVAILABLE_IOS(7_0);
UIKIT_EXTERN NSString *const UITransitionContextFromViewKey NS_AVAILABLE_IOS(8_0);
UIKIT_EXTERN NSString *const UITransitionContextToViewKey NS_AVAILABLE_IOS(8_0);
在animateTransition:中你需要处理以下过程:
- 将“to”视图插入容器视图
- 将“to”和“from”视图分别移动到自己想要的位置
- 最后,在动画完成时千万别忘了调用completeTransition: 方法 这个方法更新viewController的状态
UIViewControllerAnimatedTransitioning协议中的方法都带有一个参数:transitionContext,
这是一个系统级的对象,它符合 UIView-ControllerContextTransitioning协议,
我们可以从该对象中获取用于控制转场动画的必要信息,主要包括以下内容:
现在,我们已经开发好了动画控制器,那么最后需要做的就是,将它们应用到转场动画中:我们需要对管理转场动画的UIViewController做一些操作。
一般来说,我们只需要让UIViewController符合UIViewController-TransitioningDelegate 协议, 编写
animationController-ForPresentedController和animationControllerForDismissedController方法
然后,在推入模态视图控制器时,我们设置modalPresentationStyle为UIModalPresentationFullScreen或
UIModalPresentationCustom。我们还必须将一个符合UIViewControllerTransitioningDelegate
协议的对象设置为它的transitioningDelegate,一般来说都是推入该模态视图控制器的UIViewController
OptionsViewController *modal = [[OptionsViewController alloc]
initWithNibName:@"OptionsViewController" bundle:[NSBundle mainBundle]];
modal.transitioningDelegate = self;
modal.modalPresentationStyle = UIModalPresentationCustom;
[self presentViewController:modal animated:YES completion:nil];
必须从animationControllerForOperation得到一个有效的动画控制器
UINavigationController才会调用interactionController-ForAnimationController
@property (strong, nonatomic) UIPercentDrivenInteractiveTransition *interactionController;
- (void)awakeFromNib {
UIPanGestureRecognizer *panReconizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];
[self.navigationController.view addGestureRecognizer:panReconizer];
self.animator = [Animator new];
}
- (void)pan:(UIPanGestureRecognizer *)recognizer {
UIView *view = self.navigationController.view;
if (recognizer.state == UIGestureRecognizerStateBegan) {
CGPoint location = [recognizer locationInView:view];
if (location.x > CGRectGetMinX(view.bounds) && self.navigationController.viewControllers.count == 1) {
self.interactionController = [UIPercentDrivenInteractiveTransition new];
//如果不是storyboard 直接使用pushViewController
[self.navigationController.visibleViewController performSegueWithIdentifier:PushSegueIdentifier sender:self];
}
} else if (recognizer.state == UIGestureRecognizerStateChanged) {
CGPoint translation = [recognizer translationInView:view];
// fabs() 求浮点数的绝对值
//根据用户手指拖动的距离计算一个百分比,切换的动画效果也随着这个百分比来走
CGFloat d = fabs(translation.x / CGRectGetWidth(view.bounds));
//为目标视图加入手势(或其它交互方式)并调用 updateInteractiveTransition,传入动画时间占整过过程的百分比
[self.interactionController updateInteractiveTransition:d];
} else if (recognizer.state == UIGestureRecognizerStateEnded) {
//根据用户手势的停止状态来判断该操作是结束还是取消
//velocityInView 检测手势的速度
if ([recognizer velocityInView:view].x < 0) {
//交互完成后调用
[self.interactionController finishInteractiveTransition];
} else {
//交互取消后调用
[self.interactionController cancelInteractiveTransition];
}
self.interactionController = nil;
}
}