一 学习 在 UINavigationController 中 push 和 pop 的转场效果 

(基于iOS7 以上的转场方式)

  • 经过学习了解到,重点分三块:
  • (1)pushAnimation: TransitionPushAnimation 进场效果动画管理器 (NSObject并遵守UIViewControllerAnimatedTransitioning协议)
  • (2)popAnimation:   TransitionPopAnimation  出场效果动画管理器 (NSObject并遵守UIViewControllerAnimatedTransitioning协议) 
  • (3)navigationPerformerObject: TransitionNavigationPerformer 对象操控转场 (设置转场动画代理遵从 UINavigationControllerDelegate协议)
用同一逻辑写了两个效果 来看, 转场代理方法实现差别不大. 关键 是 进出场效果,有人说”你的想象无限 动画效果无限”. 所以掌握了转场动画基本实现基本技巧后,就应该尝试深入研究一下动画效果的实现.这里强调实现转场动画原理和实现过程
   1 进场效果 和 出场效果 主要实现 UIViewControllerAnimatedTransitioning 协议的两个方法:
        (1)动画切换的持续时间,以秒为单位

- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
        (2)动画执行内容

- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext

注意要点: 判断 动画执行完成结果状态

当用户做手指跟随操作的过程中,根据操作的finished位置 要判断此时应该是该结束动画 还是取消动画.

[transitionContext completeTransition:![transitionContext transitionWasCancelled]];

下面手势 就是 判断用户手势跟随进度  :

  if ( progress > 0.5) {// 时为 完成 触发"返回"操作

[self.interactionController finishInteractiveTransition];//transitionContext.transitionWasCancelled 会得到NO的回调
      } else {// 反之 为取消 保留当前页面

[self.interactionController cancelInteractiveTransition];//transitionContext.transitionWasCancelled 会得到YES的回调

}

起初因为 [transitionContext transitionWasCancelled] 状态没注意导致 页面过渡 就那么卡住了 或者 页面空白,种种动画效果滞涩的问题都是 状态信号控制不好导致的

   2 这里需要遵从UINavigationControllerDelegate协议的两个方法,这两个方法在对屏幕进行翻转的时候对导航栏控制器变化的动画设置 :

- (nullable id <UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController
interactionControllerForAnimationController:(id <UIViewControllerAnimatedTransitioning>) animationController NS_AVAILABLE_IOS(7_0); - (nullable id <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
animationControllerForOperation:(UINavigationControllerOperation)operation
fromViewController:(UIViewController *)fromVC
toViewController:(UIViewController *)toVC NS_AVAILABLE_IOS(7_0);

通常写法是把导航去设置和代理方法写在对应的视图控制器里面,这里我们创建 一个对象TransitionNavigationPerformer 遵循UINavigationControllerDelegate代理方法,这样封装,耦合性低,并且代码可移植性更强.

 

#import <Foundation/Foundation.h>
@class TransitionPushAnimation;
@class TransitionPopAnimation; @interface TransitionNavigationPerformer : NSObject <UINavigationControllerDelegate> - (instancetype)initWithNav:(id)nav; //为了操控 self.navigationController @property (weak, nonatomic) UINavigationController *navigationController; //这里强调单项弱引用 @property (strong, nonatomic) TransitionPushAnimation *pushAnimation; @property (strong, nonatomic) TransitionPopAnimation *popAnimation; @property (strong, nonatomic) UIPercentDrivenInteractiveTransition *interactionController;//没做特殊处理 就是默认系统创建 用来控制动画效果进度状态 @end
//
// TransitionNavigationPerformer.m
// SectionDemo
//
// Created by HF on 17/3/29.
// Copyright © 2017年 HF-Liqun. All rights reserved.
// #import "TransitionNavigationPerformer.h"
#import "TransitionPopAnimation.h"
#import "TransitionPushAnimation.h" @interface TransitionNavigationPerformer ()
{
UIScreenEdgePanGestureRecognizer *panGesture;
} @end @implementation TransitionNavigationPerformer - (instancetype)initWithNav:(id)nav
{
self = [super init];
if (self) { self.navigationController = nav;
// 在导航控制器的视图上添加pan手势 --> 需要从边缘进行拖动,在控制器转换的时候是有用 "UIScreenEdgePanGestureRecognizer"
panGesture = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];
panGesture.edges = UIRectEdgeLeft; //主要用作返回 left
[self.navigationController.view addGestureRecognizer:panGesture]; // 初始化动画方案
self.pushAnimation = [[TransitionPushAnimation alloc] init];
self.popAnimation = [[TransitionPopAnimation alloc] init];
}
return self;
} - (void)dealloc
{ //这里目的防止取消切换效果后 导航控制器仍然会对手势持有
[panGesture removeTarget:self action:@selector(pan:)];
self.interactionController = nil;
} - (void)pan:(UIScreenEdgePanGestureRecognizer *)recognizer
{
UIView *view = self.navigationController.view;
CGFloat progress = [recognizer translationInView:view].x / (view.bounds.size.width * 1.0);
progress = MIN(1.0, MAX(0.0, progress)); if (recognizer.state == UIGestureRecognizerStateBegan) {
// 创建过渡对象,弹出viewController
self.interactionController = [[UIPercentDrivenInteractiveTransition alloc] init];
[self.navigationController popViewControllerAnimated:YES];
}
else if (recognizer.state == UIGestureRecognizerStateChanged) {
// 更新 interactive transition 的进度
[self.interactionController updateInteractiveTransition:progress];
}
else if (recognizer.state == UIGestureRecognizerStateEnded || recognizer.state == UIGestureRecognizerStateCancelled) {
// 完成或者取消过渡
if (progress > 0.5) {
[self.interactionController finishInteractiveTransition];
}
else {
[self.interactionController cancelInteractiveTransition];
}
self.interactionController = nil;
}
} #pragma mark - UINavigationControllerDelegate - (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
animationControllerForOperation:(UINavigationControllerOperation)operation
fromViewController:(UIViewController *)fromVC
toViewController:(UIViewController *)toVC
{
if (operation == UINavigationControllerOperationPush) {
return self.pushAnimation;
}
else if (operation == UINavigationControllerOperationPop) {
return self.popAnimation;
}
return nil;
} - (id<UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController
interactionControllerForAnimationController:(id<UIViewControllerAnimatedTransitioning>)animationController {
// 检查是否是我们的自定义过渡
if ([animationController isKindOfClass:[TransitionPushAnimation class]] || [animationController isKindOfClass:[TransitionPopAnimation class]]) {
return self.interactionController;
}
else {
return nil;
}
}
@end

3 方法调用

(1)在使用的时候 要添加self.navigationController.delegate = TransitionNavigationPerformer 对象, 不需要就设置为nil

(2)页面viewWillDisappear 一定要立即取消代理方法 防止交互崩溃 .

参考Demo:SectionDemo

效果:

  

参考:

http://www.open-open.com/lib/view/open1408677710366.html

http://www.cocoachina.com/ios/20150811/12986.html

https://github.com/seedante/iOS-Note/wiki/ViewController-Transition

iOS 视图控制器转场动画/页面切换效果/跳转动画 学习的更多相关文章

  1. iOS 视图控制器转场详解

    iOS 视图控制器转场详解 前言的前言 唐巧前辈在微信公众号「iOSDevTips」以及其博客上推送了我的文章后,我的 Github 各项指标有了大幅度的增长,多谢唐巧前辈的推荐.有些人问我相关的问题 ...

  2. 笔记-iOS 视图控制器转场详解(上)

    这是一篇长文,详细讲解了视图控制器转场的方方面面,配有详细的示意图和代码,为了使得文章在微信公众号中易于阅读,seedante 辛苦将大量长篇代码用截图的方式呈现,另外作者也在 Github 上附上了 ...

  3. iOS(视图控制器转场)

    转场需要提供转场代理,不使用默认的代理则需要自己实现代理方式,有UINavigationController.UITabBarController.UIViewController三种代理,实现以下三 ...

  4. iOS 动画学习之视图控制器转场动画

    一.概述 1.系统会创建一个转场相关的上下文对象,传递到动画执行器的animateTransition:和transitionDuration:方法,同样,也会传递到交互Controller的star ...

  5. 在uwp仿IOS的页面切换效果

    有时候我们需要编写一些迎合IOS用户使用习惯的uwp应用,我在这里整理一下仿IOS页面切换效果的代码. 先分析IOS的页面切换.用户使用左右滑动方式进行前进和后退,播放类似于FlipView的切换动画 ...

  6. iOS视图控制器的生命周期

    今天面试有一道面试题因为回答不好,因为也不经常涉及所以有点模糊,我选择了最保守的回答,没有展开写出我对这个问题的理解. 问题:IOS 开发 loadView 和 viewDidLoad 的区别? 经过 ...

  7. [Swift通天遁地]九、拔剑吧-(7)创建旋转和弹性的页面切换效果

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...

  8. [Swift通天遁地]九、拔剑吧-(8)创建气泡式页面切换效果

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...

  9. Android - TabHost 与 Fragment 制作页面切换效果

    Android - TabHost 与 Fragment 制作页面切换效果 Android API 19 , API 23 三个标签页置于顶端 效果图: 在文件BoardTabHost.java中定义 ...

随机推荐

  1. java.lang.NoClassDefFoundError: org/junit/rules/TestRule

    错误原因:通过定位发现是找不到TestRule这个类,检查项目引用的Junit版本为4.7,发现TestRule是在Junit版本4.10后添加的新特性 解决方法:把junit版本由4.7改成4.10

  2. IIS下PHP的ISAPI和FastCGI比较

    在Windows IIS 6.0下配置PHP,通常有CGI.ISAPI和FastCGI三种配置方式,这三种模式都可以在IIS 6.0下成功运行,下面我就讲一下这三种方式配置的区别和性能上的差异. 1. ...

  3. linux 分卷压缩命令

    linux 分卷压缩命令 1.使用tar分卷压缩 格式 tar cvzf - filedir | split -d -b 50m - filename 样例: tar cvzf - ./picture ...

  4. python3----ljust rjust center

    Python中打印字符串时可以调用ljust(左对齐),rjust(右对齐),center(中间对齐)来输出整齐美观的字符串,使用起来非常简单,包括使用第二个参数填充(默认为空格).看下面的例子就会明 ...

  5. iOS内存管理之浅见

    当我们用alloc.new.copy创建对象时,对象的应用计数为1,当把这个对象retain时.引用计数+1.当对这个对象发送release消息时,引用计数-1,当对象的引用计数为0时,系统回收这个对 ...

  6. kali linux下更新163源可使用RPM

    在没有安装163源之前 更新163源 1.在终端输入#leafpad /etc/apt/sources.list 2.打开网页 http://mirrors.163.com/.help/debian. ...

  7. javascript获取客户端默认打印机

    JS <script language="javascript"> function startRequest() { var oShell = new ActiveX ...

  8. idea 右下角不显示git分支

    开发工程中遇到idea右下角不显示git分支问题: 解决方案:查找资料说是需要打开VCS->Enable version control. 但是Enable version control 已经 ...

  9. 记录--Gson、json转实体类、类转json

    需要导入Gson jar包 最近在做一个java web service项目,需要用到jason,本人对java不是特别精通,于是开始搜索一些java平台的json类库. 发现了google的gson ...

  10. coursera 《现代操作系统》 -- 第七周 存储模型(1)

    虚拟地址 隔离进程,便于管理. 问:为什么不直接划分物理地址为一块一块,直接管理,而要做一层虚拟地址的映射呢? 栈和堆 Differences between Stack and Heap Stack ...