代码地址如下:
http://www.demodashi.com/demo/12905.html

运行效果

实现思路

创建pan手势,添加到页面中,监听手势的动作。重写push的方法,在push之前截图保存到数组。重写pop的方法,在pop之前删除截图。pop的动画效果是利用截图的image添加到topView上,从视觉效果上实现缩放、平移的动画效果。以下是具体的实现思路:

1.创建Pan手势识别器

 delegate = self
let panRecognizer = UIPanGestureRecognizer(target: self, action: #selector(paningGestureReceive(recoginzer:)))
panRecognizer.delegate = self
view.addGestureRecognizer(panRecognizer)
//实现侧滑返回
interactivePopGestureRecognizer?.delegate = self

2.实现手势的相应事件

//MARK: - Events
@objc func paningGestureReceive(recoginzer:UIPanGestureRecognizer) {
//如果只有一个控制器或者不允许全屏返回,return
if self.viewControllers.count <= 1 || !canDragBack {
return
} let touchPoint = recoginzer.location(in: UIApplication.shared.keyWindow) switch recoginzer.state {
case .began:
isMoving = true
startTouch = touchPoint
if backgroundView == nil {
let frame = TOP_VIEW?.frame
backgroundView = UIView(frame: CGRect(x: 0, y: 0, width: (frame?.size.width)!, height: (frame?.size.height)!))
TOP_VIEW?.superview?.insertSubview(backgroundView!, belowSubview: TOP_VIEW!) blackMask = UIView(frame: CGRect(x: 0, y: 0, width: (frame?.size.width)!, height: (frame?.size.height)!))
blackMask?.backgroundColor = UIColor.black
backgroundView?.addSubview(blackMask!)
}
backgroundView?.isHidden = false
if lastScreenShotView != nil {
lastScreenShotView?.removeFromSuperview()
} let lastScreenShot = screenShotsList.lastObject as! UIImage
lastScreenShotView = UIImageView(image: lastScreenShot)
backgroundView?.insertSubview(lastScreenShotView!, belowSubview: blackMask!) break
case .ended:
//手势结束,判断是返回还是回到原位
if touchPoint.x - (startTouch?.x)! > 50 {
UIView.animate(withDuration: 0.3, animations: {
self.moveView(withX: self.kMAXWidth)
}, completion: { (finished:Bool) in
self.popViewController(animated: false)
var frame = self.TOP_VIEW?.frame
frame?.origin.x = 0
self.TOP_VIEW?.frame = frame!
self.isMoving = false
self.backgroundView?.isHidden = true
// End paning,remove last screen shot
self.customAnimation.removeLastScreenShot()
})
} else {
UIView.animate(withDuration: 0.3, animations: {
self.moveView(withX: 0)
}, completion: { (finished:Bool) in
self.isMoving = false
self.backgroundView?.isHidden = true
})
}
return //直接返回,不在往下执行
case .cancelled:
UIView.animate(withDuration: 0.3, animations: {
self.moveView(withX: 0)
}, completion: { (finished:Bool) in
self.isMoving = false
self.backgroundView?.isHidden = true
})
return
default:
break
}
if isMoving! {
self.moveView(withX: touchPoint.x - (startTouch?.x)!)
}
}

3.创建截图需要的backgroundView和作为遮罩的blackMask,存放截图所需的数组

if backgroundView == nil {
let frame = TOP_VIEW?.frame
backgroundView = UIView(frame: CGRect(x: 0, y: 0, width: (frame?.size.width)!, height: (frame?.size.height)!))
TOP_VIEW?.superview?.insertSubview(backgroundView!, belowSubview: TOP_VIEW!) blackMask = UIView(frame: CGRect(x: 0, y: 0, width: (frame?.size.width)!, height: (frame?.size.height)!))
blackMask?.backgroundColor = UIColor.black
backgroundView?.addSubview(blackMask!)
}
backgroundView?.isHidden = false
if lastScreenShotView != nil {
lastScreenShotView?.removeFromSuperview()
} let lastScreenShot = screenShotsList.lastObject as! UIImage
lastScreenShotView = UIImageView(image: lastScreenShot)
backgroundView?.insertSubview(lastScreenShotView!, belowSubview: blackMask!)

4.在push前截图,并保存

override func pushViewController(_ viewController: UIViewController, animated: Bool) {
if self.viewControllers.count >= 1 {
let screenshot = getScreenshot()
if screenshot != nil {
screenShotsList.add(screenshot!)
}
}
super.pushViewController(viewController, animated: animated)
}

5.重写常用的pop方法,在pop前删除相应的截图

@discardableResult
override func popViewController(animated: Bool) -> UIViewController? {
screenShotsList.removeLastObject()
return super.popViewController(animated: animated)
} override func popToViewController(_ viewController: UIViewController, animated: Bool) -> [UIViewController]? {
var removeCount = 0
for i in stride(from: viewControllers.count-1, to: 0, by: -1) {
if viewController == viewControllers[i] {
break
}
screenShotsList.removeLastObject()
removeCount = removeCount+1
}
customAnimation.removeCount = removeCount
return super.popToViewController(viewController, animated: animated)
} override func popToRootViewController(animated: Bool) -> [UIViewController]? {
screenShotsList.removeAllObjects()
customAnimation.removeAllScreenShot()
return super.popToRootViewController(animated: animated)
}

到此处能实现手势整体返回的效果,要实现点击返回按钮也能整体返回,需要自定义返回动画。实现协议UIViewControllerAnimatedTransitioning

6.让navigationController遵守UINavigationControllerDelegate实现下面的方法,在方法里面可根据operation判断需要自定义的类型(pop/push)

 func navigationController(_ navigationController: UINavigationController,
animationControllerFor operation: UINavigationControllerOperation,
from fromVC: UIViewController,
to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning?

7.使用一个类实现UIViewControllerAnimatedTransitioning协议

func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval

//定义动画
func animateTransition(using transitionContext: UIViewControllerContextTransitioning)

项目结构图

KINavigationController使用演示例子

代码地址如下:
http://www.demodashi.com/demo/12905.html

注:本文著作权归作者,由demo大师代发,拒绝转载,转载需要作者授权

KINavigationController使用演示例子的更多相关文章

  1. 三层架构的OPP实现的演示例子

    例子:演示会员添加与删除 说明:因为是简单的例子,我们用在屏幕上打印"添加成功"和"删除成功"这几个字表示会员的添加与删除,仅仅为了演示如何实现三层的分离: 1 ...

  2. 百度webuploader 上传演示例子

    前端代码 <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="baiduWebU ...

  3. 实例演示Android异步加载图片

    本文给大家演示异步加载图片的分析过程.让大家了解异步加载图片的好处,以及如何更新UI.首先给出main.xml布局文件:简单来说就是 LinearLayout 布局,其下放了2个TextView和5个 ...

  4. 实例演示Android异步加载图片(转)

    本文给大家演示异步加载图片的分析过程.让大家了解异步加载图片的好处,以及如何更新UI.首先给出main.xml布局文件:简单来说就是 LinearLayout 布局,其下放了2个TextView和5个 ...

  5. Web三维技术:Flash Builder+away3d平台搭建(含演示视频)

    转自:http://www.cnblogs.com/beer/archive/2011/07/08/2101492.html 前言:作为页面中实验设备的显示层,需要一个swf作为显示的UI.虽然可以用 ...

  6. 5、Cocos2dx 3.0小游戏开发的例子寻找测试三个简单的介绍和总结

    繁重的劳动开发商,当转载请注明出处:http://blog.csdn.net/haomengzhu/article/details/27186557 測试例子简单介绍 Cocos2d-x 为我们提供了 ...

  7. 转 UNIGUI安装教程、使用例子

    转 UNIGUI安装教程.使用例子 http://my.oschina.net/u/582827/blog/203429?p={{currentPage-1}} 转 uniGui安装教程.使用例子 发 ...

  8. 5、Cocos2dx 3.0游戏开发找小三之測试例子简单介绍及小结

    重开发人员的劳动成果.转载的时候请务必注明出处:http://blog.csdn.net/haomengzhu/article/details/27186557 測试例子简单介绍 Cocos2d-x ...

  9. 微服务+DDD代码结构例子

    这是一个基本的微服务+DDD演示例子: 基于 Spring Boot 1.5.6 , Spring Cloud Edgware.SR4 Version 微服务 + DDD,个人觉得应该是首先是从微服务 ...

随机推荐

  1. 【转载】Synflood code

    ''' Syn flood program in python by Tequila/e credits to Silver Moon for base's of syn packets. r s s ...

  2. 欧拉函数O(sqrt(n))与欧拉线性筛素数O(n)总结

    欧拉函数: 对正整数n,欧拉函数是少于或等于n的数中与n互质的数的数目. POJ 2407.Relatives-欧拉函数 代码O(sqrt(n)): ll euler(ll n){ ll ans=n; ...

  3. 洛谷——P2719 搞笑世界杯

    题目背景 很久很久以后,一次世界杯,. 题目描述 随着世界杯小组赛的结束,法国,阿根廷等世界强队都纷纷被淘汰,让人心痛不已. 于是有人组织了一场搞笑世界杯,将这些被淘汰的强队重新组织起来和世界杯一同比 ...

  4. ( 转 ) .net 操作 JWT

    GitHub: https://github.com/jwt-dotnet/jwt 1.JWT定义 JWT(Json Web Token)是一种用于双方之间传递安全信息的简洁的.URL安全的表述性声明 ...

  5. mdadm Raid5 /dev/md0 lost a disk and recovery from another machine

    centos -- how to add a new disk into a mdadm raid5 /dev/md0 which lost a /dev/sdc1 disk and  revoery ...

  6. python3开发进阶-Djamgo框架中的JSON和AJAX

    阅读目录 什么是JSON 什么是AJAX AJAX常见的应用情景 jQery实现AJAX AJAX请求如何设置csrf_token AJAX上传文件 补充Django内置的serializers 一. ...

  7. SpringMVC(流程+第一个Demo)

    一.流程图 用户发送请求至前端控制器DispatcherServlet DispatcherServlet收到请求调用HandlerMapping处理器映射器. 处理器映射器根据请求url找到具体的处 ...

  8. java--模板方法模式

    /* 需求:获取一段程序的运行时间 原理:获取程序开始和结束的时间并相减即可 获取时间:用java中已有的一个类:System.currentTimeMillis(); 当代码完成优化后,就可以解决这 ...

  9. Getting terminal width in C?

    转:http://stackoverflow.com/questions/1022957/getting-terminal-width-in-c 方法一: #include <sys/ioctl ...

  10. 最短路径之迪杰斯特拉算法的Java实现

    Dijkstra算法是最短路径算法中为人熟知的一种,是单起点全路径算法.该算法被称为是“贪心算法”的成功典范.本文接下来将尝试以最通俗的语言来介绍这个伟大的算法,并赋予java实现代码. 一.知识准备 ...